Blunt_Axe_Basic Project

Copyright:(c) sarbayo, 2001,02,03,04
Alpha Version 1.05

_Bxbasm_
(Blunt Axe Basic)

Welcome to Bxbasm

TABLE OF CONTENTS:
What is Bxbasm	....................................	3
How to use Bxbasic	..............................	4
Compiling Error	....................................	5
Bxbasic Commands	....................................	6
String and Math functions	........................	7
Examples: line numbers, REM, CLS, PRINT, BEEP, END		8
GOTO	................................................	9
LET	................................................	10
LOCATE	..........................................	12
Math expressions	....................................	13
Optional usage: line numbers, REM, LET	............	14
Block Labels	....................................	15
CLEAR	................................................	17
Numeric data types	..............................	19
String variables	....................................	24
PRINT	................................................	25
GOSUB/RETURN	....................................	26
FOR/NEXT	..........................................	30
Power and Modulus	....................................	32
IF/ELSE	..........................................	33
String functions	....................................	35
INKEY$	..........................................	39
INPUT		..........................................	40
INPUT$	..........................................	41
LINE INPUT	..........................................	42
Algebraic functions	..............................	43
Disk File I/O: OPEN, CLOSE	........................	45
EOF	................................................	48
WRITE		..........................................	50
LINE INPUT#	..........................................	52
PRINT#	..........................................	53
Random I/O	..........................................	54
FIELD, LSET, RSET, PUT	..............................	55
GET	................................................	56
I/O string functions:  MKD$, MKS$, MKI$, CVD, CVS, CVI	58
Count to A Million program	........................	62
Summary	..........................................	63

What is Bxbasm ?
What is Bxbasm and the Blunt_Axe_Basic Project ?
Bxbasm is a compiler.
Bxbasic is a language subset or dialect of Basic.
Bxbasm is a work in progress and at this stage of developmentis a Console Mode 32 bit Native Code Compiler. 
The Bxbasic dialect is presently a subset of and is not yet a complete implementation of the QBasic/QuickBasic_4.5 dialect and is currently in development.

It is fully intended to develop Bxbasic into:
•	a full featured QBasic/QuickBasic-4.5 and RapidQ work-alike, 
•	running in 32 bit Console and Windows Modes,
•	as a Native Code Compiler.

This is not a commercial product or project! 
It is not intended for this project to become a commercial product. 

How to use Bxbasic:
The user need not be familiar with assembly language, nor how to use a compiler, assembler or linker, to compile Bxbasic scripts. Bxbasic comes with a text editor (Qedit) which allows the programmer to load, create, edit and save or cut-n-paste basic scripts and compile and execute those programs directly from within Qedit.

The Bxbasic components are:
•	Bxbasm.exe: a stand-alone Basic Compiler. A Bxbasic script, written using Notepad, Wordpad , Edit, or any other ascii text editor may be compiled into x86 assembly language while in a Dos Window or in Console Mode, (i.e. command line).
•	Qeditor.exe: is a component of Masm32 and is a stand alone ascii text editor. Qedit is the key to the ease of use of Bxbasic.
•	ML.exe: is the Masm32 assembler.
•	Link.exe:is the Masm32 linker.

Bxbasm may be used in the following manner:
*) follow the instruction, exactly, for installing Bxbasm,
*) from Windows, load Qeditor,
*) enter, or cut-n-paste the following text: (case is sensitive)

' begin:>

	CLS
	BEEP
	PRINT "hello world!
	END

 ' end:>

*) now, from the File menu, select Save
   and save the file as TEST1.BAS, in the \Masm32\Bxbasm\ directory,
*) from the Menu-bar, select Compiler
   and then from the drop-down menu, select Console Compile,

a Dos-Box will open and dialog will appear on the screen:
•		first from: Bxbasic, 
•	 	  then the: Assembler, (this will take several seconds),
•		  then the: Linker,

and finally, a listing of "Test1" files:
	Test1.bas
	Test1.asm
	Test1.obj
	Test1.exe		(examine the file size for Test1.exe)

*) press the [enter] key and then close the Dos-Box: [X]
*) to execute Test1.exe:
	from the Menu-bar, again select Compiler
	and from the drop-down menu, select Run Program

*) the Dos-Box remains open until you press [enter].

That's all there is to it!!!

Was there an error compiling?:
*)If there was an error in the Basic script or any other error during compile, assembly or linking, the error message would be displayed in the Dos-Box, indicating what the error was.
Bxbasm does have a limited amount of error checking and if it encounters an error, a message will be displayed and the compile will terminate at the point of error. Bxbasm will not compile and assemble a program with a known error.

*)If you did not follow the instructions exactly for installing Masm32 and Bxbasm, that will cause an error!

*)There are aspects of Masm32 that require that it be installed in the ROOT directory, ie: C:\Masm32\...
Masm32 will not work any other way. Attempting to relocate the \Masm32\ directory and it's entire contents to a subdirectory elsewhere on the drive  will not work!

What functions does Bxbasic support?
Since Bxbasic is a work in progress, as of this date it consists of a subset of the Basic language. New commands and functions are being added at regular intervals.
At present the KEYWORD list is as follows:
	Keyword:		Description:
	ASM          	passes assembly language code to the assembler
	BEEP			beep sound on pc speaker
	BREAK           	used in a WHILE, DO, or LOOP routine
	CLEAR			erase variables
	CLOSE			terminate disk file access
	CLS			clear screen
	CHDIR			change disk directory
	CHDRIVE		change drives
	COLOR			selects foreground and background colors
	DIM *       	dimensions arrays, *(presently strings)
	DO/WHILE		creates a loop routine
	END			terminate program
      FIELD			fields strings to I/O Buffer
	FOR/NEXT		creates a loop routine
	FILES			displays directory file list
	GET			device input, random access
	GOSUB/RETURN	branch to, return from subroutine
	GOTO			absolute jump to line label
	IF/ELSEIF/ELSE/ENDIF
				conditional expression, alternate condition
				default action, condition terminator
	INPUT			keyboard input
	INPUT#		device input
	KILL			delete file
	LET			assignment to variable
	LINE INPUT		keyboard input
	LINE INPUT#		device input
	LOCATE		position cursor on console screen
	LSET			moves data to I/O Buffer
	LOOP/ENDLOOP	creates a loop routine
	LPRINT		text output to line printer on LPT1
	MKDIR			make new directory
	NAME/RENAME		rename a disk file
	OPEN			open disk file for access
	PRINT			display data to console screen
	PRINT#		write text image to file
	PUT			device output
	REM			comments. may substitute with: '
	RSET			moves data to i/o buffer
	RANDOM		produce a pseudo-random number
	READ#			device input, file
	RMDIR			remove directory
	SHELL			drop to DOS console
	THEN			used with IF statement
	WRITE#		device output
	WHILE/WEND		creates a loop routine

**Note:
Bxbasic is case sensitive. All keywords and functions must appear in upper case.

Additionally, there are several string, algebraic and device functions.
Strings:
	Function:		Description:
	CHR$()		ascii character assignment
	DATE$			returns the current date
	LEFT$()		left string slicing
	MID$()		middle string slicing
	MKD$()		convert double precision to string (file I/O)
	MKI$()		convert integer to string (file I/O)
	MKS$()		convert single precision to string (file I/O)
	RIGHT$()		right string slicing
	SPACE$()		blank space(s) assignment
	STR$()		numeric to string assignment
	STRING$()		ascii character string assignment
	TIME$			returns the current time

Algebraic/Numeric:
	Function:		Description:
	ABS(exp)		absolute value of expression
	ASC(str$)		numeric value of ascii character
	ATN(exp)		arctangent of expression
	ATN2(exp)		arctangent of y/x
	ACOS(exp)		arc cosine of x
	ASIN(exp)		arc sine of x
	COS(exp)		cosine of expression
	COSH(exp)		hyperbolic cosine of x
	CEIL(exp)		smallest whole number not less than x
	CLOCK()		elapsed time in clock ticks
	CVD(str$)		convert string to double precision (file I/O)
	CVI(str$)		convert string to integer (file I/O)
	CVS(str$)		convert string to single precision (file I/O)
	FLOOR(exp)		largest whole number not greater than x
	HYPOT(exp)		length of hypotenuse for x and y
	INT(exp)		integer value of a number
	LEN(str$)		length of ascii string
	LOG(exp)		logarithm of x
	LOG10(exp)		base 10 logarithm of x
	RAND(seed)		seeds random number generator
	SIN(exp)		sine of expression
	SINH(exp)		hyperbolic sine of x
	SQRT(exp)		square root of expression
	TAN(exp)		tangent of expression
	TANH(exp)		hyperbolic tangent of x
	VAL(str$)		numeric value of a number-string

Device:
	Function:		Description:
	INKEY$		a single keyboard character
	INPUT$		a string of keyboard characters
	EOF(hndl)		returns true if end-of-file
	LOC(hndl)		returns current file-record position
	LOF(hndl)		returns length of file in bytes

Usage examples:
Here are some 'cut-n-paste' examples that you can try. Merely 'cut-n-paste' them to the Qedit text editor and save them as Test.bas. Then compile and execute them.

Line Numbers, REM, CLS, PRINT, BEEP, END:
In it's most basic from, the program statement looks like this:

1 REM  test.bas version 1
2 CLS
3 PRINT "hello world!"
4 BEEP
5 END

Line Numbers:
Program lines may or may not be numbered. Line numbers have a minimal practical use and their usage is not recommended, but, their usage is included for compatibility. If line numbers are used, the must appear in column #1, the far left side, only.
Line numbers will appear here for illustrative purposes only.
In the above example:
REM		in line 1: is a comment,
CLS		in line 2: clears the display screen
PRINT		in line 3: prints a message on the display screen
BEEP		in line 4: sounds a beep on the pc speaker
END		in line 5: terminates the program

PRINT		The PRINT command takes the form:
		PRINT		(generates a newline)
	or	PRINT "text"
	or	PRINT variable
	or	PRINT (expression)

END		Every program must have an END command. 
		However, it need not be at the end of the program.

GOTO:
In the example below, using the GOTO command:
	 line 5:	performs an absolute jump to line #9
	line 11:	an absolute jump to line #6
	 line 8:	terminates the program

1 REM  test.bas version 2
2 CLS
3 PRINT "hello world!"
4 BEEP
5 GOTO 9
6 PRINT "Back at line #6"
7 PRINT "The End."
8 END
9 PRINT "Now at line #9"
10 BEEP
11 GOTO 6

LET:
The LET command has the form:
		LET variable = value
	or	LET variable = variable
	or	LET variable = "text string"

In this example, 
	line 5:	keyword LET assigns a numeric value to integer 
			variable: "abc". 

1 REM  test.bas version 3
2 CLS
3 PRINT "hello world!"
4 BEEP
5 LET abc = 100
6 PRINT "abc = 100"
7 END

Variable names are limited to 32 alpha-numeric characters only. No punctuation characters are permitted (at this time).
Variables are distinguished into five types:
	Symbol:	Type:
	  $		character string
	  #		double precision floating point
	  !		single precision float
	  %		long integer
	 none		integer

If a variable name has no type specifier, it is assumed to be of type integer.

Here, in:
line 12 thru 14:		three integer assignments are made.
	  line 15:		variable 'abc' is re-assigned a new value:

1 REM  test.bas version 4
2 CLS
3 PRINT "hello world!"
4 BEEP
' ...
12 LET abc = 100
13 LET xyz = 999
14 LET qwerty = 12345
15 LET abc = 32123
16 END

In this next example, variables: abc, xyz and qwerty are assigned values. 
Then PRINT command is used to display each variable's contents.

1 REM  test.bas version 5
2 CLS
3 PRINT "hello world!"
4 LET abc = 100
5 PRINT abc,
6 LET xyz = 999
7 LET qwerty = 12345
8 LET abc = 32123
9 PRINT xyz,
10 PRINT qwerty,
11 PRINT abc
12 PRINT "The End."
13 END

LOCATE:
The LOCATE command has the form:
		LOCATE row, column

In lines 4 and 5, variables: row and column are each given a value.
Then on line 6, the LOCATE command it used to position the cursor,
 at: 	   Row: 2
	Column: 10

and again in line 10:

1 REM  test.bas version 6
2 CLS
3 PRINT "hello world!"
4 LET Row = 2
5 LET Column = 10
6 LOCATE Row, Column
7 PRINT "hello world!"
8 LET Row = 4
9 LET Column = 20
10 LOCATE Row, Column
11 PRINT "hello world!"
12 END

The console mode screen is character based and has the dimensions of 25x80.
The upper left corner is row 0, column 0.

Math Expression Assignments:
A variable assignment can be in the form of a mathematical expressions.
As shown in line 4:

1 REM  test.bas version 7
2 CLS
3 PRINT "hello world!"
4 LET abc = 2 + 2
5 PRINT abc
6 END

Complex algebraic expressions can be used in an assignment:

1 REM  test.bas version 8
2 CLS
3 PRINT "hello world!"
4 LET xylophone = 50
5 LET yazoo = 100
6 LET abc = yazoo/xylophone
7 LET xyz = yazoo/10
8 LOCATE abc , xyz
9 PRINT "hello world!"
10 LET quasar = 2
11 LET zapp = 4
12 LET abc = (quasar * quasar * zapp + zapp)/5
13 LET xyz = ((quasar*quasar)*zapp)+zapp
14 LOCATE abc, xyz
15 PRINT "hello world!"
50 END

Optional: Line Numbers, REM, LET:
As stated previously, line numbers are entirely optional and in most cases un-needed. The only time they may actually be needed is as line labels.
Here, even the REM is optional, as well. The REM keyword may be replaced with the apostrophy (') character.
Blank or empty lines are ignored by the compiler and often times help to  make the source code more readable.
Also, the LET keyword is optional.

'  test.bas version 9
'
  CLS
  PRINT "hello world!"
  LET xylophone = 50
  LET yazoo = 100
  LET abc = yazoo/xylophone
  xyz = yazoo/10
'
  LOCATE abc , xyz
  PRINT "hello world!"
' ------------------------------------------
  quasar = 2
  zapp = 4
  abc = (quasar * quasar * zapp + zapp)/5
  xyz = ((quasar * quasar) * zapp) + zapp
'
  LOCATE abc, xyz
  PRINT "hello world!"
' ------------------------------------------
'
  PRINT
  PRINT " 2*(3+4)*5/10 = ";
  abc = 2*(3+4)*5/10
  PRINT abc
'
TheEnd:
  END
' ------------------------------------------

In the above code, examine the PRINT statements. 
PRINT has several forms:
	PRINT abc		prints variable followed by newline
	PRINT			generates a newline
	PRINT ""		also a newline
	PRINT a;		semi-colon does not send a newline
	PRINT a,		comma sends a tab, no newline

BLOCK LABELS:
"Block Labels" are preferred over line numbers and give symbolic meaning to a routine or a block of code. 

'  test.bas version 10
  CLS
'               now jump to a block label
  GOTO OverThere
'
TheBeginning:
  PRINT "We"; CHR$(39); "re at The Beginning!"
  GOTO TheEnd
'
There:
  PRINT "We"; CHR$(39); "re There!"
  GOTO TheBeginning
'
JumpBack1:
  PRINT "We Jumped Back 1!"
  GOTO There
'
OverThere:
  PRINT "We"; CHR$(39); "re Over There!"
  GOTO JumpBack1
'
TheEnd:
  END
' ------------------------------------------

**NOTE
(Neither single nor double quotes may be used within a text string, as they are mis-interpreted by the assembler as being assembler directives. As in the above example, ascii character 39 is a single quote (') mark.)

Where used, line Labels or "Block Labels" must start at the far left column, as shown above. 
A Label name:
*	may contain up to 32 alpha-numeric characters,
*	must contain no punctuation characters,
*	must be terminated by a colon (:),
*	is case sensitive, so:	label:
					Label:
				and 	LABEL:   are each unique.

When used with a GOTO statement, the label name is not terminated by the colon. i.e.:
		GOTO Label1

'  test.bas version 11
Start1:
  CLS
  GOTO Jump
Return:
  GOTO TheEnd
Jump:
  PRINT "hello world!"
' ------------
  LET xylophone = 50
  LET yazoo = 100
  LET abc = yazoo/xylophone
  xyz = yazoo/10
  LOCATE abc , xyz
  PRINT "hello world!"
' ------------------------------------------
  quasar = 2
  zapp = 4
  abc = (quasar * quasar * zapp + zapp)/5
  xyz = ((quasar * quasar) * zapp) + zapp
  LOCATE abc, xyz
  PRINT "hello world!"
' ------------------------------------------
  PRINT
  PRINT " 2*(3+4)*5/10 = ";
  abc = 2*(3+4)*5/10
  PRINT abc
  GOTO Return
TheEnd:
  END
' ------------------------------------------

CLEAR:
The CLEAR command has the form:
		CLEAR
	or	CLEAR variable-name

'  test.bas version 12
Start1:
  CLS
  PRINT "hello world!"
' ------------
  LET xylophone# = 50.3
  LET yazoo# = 101.25
  LET abc = yazoo#/xylophone#
  xyz = yazoo#/10
  quasar = 2
  zapp = 4
  abc = (quasar * quasar * zapp + zapp)/5
  xyz = ((quasar * quasar) * zapp) + zapp
  abc = 2*(3+4)*5/10
'
  CLEAR
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

A plain CLEAR statement will erase all variables.
If a variable does not any longer exist, or has previously been erased, the CLEAR command will ignore that fact. It will not cause an error.

In the example below, the CLEAR command may be used selectively to erase variables.

'  test.bas version 13
Start1:
  CLS
  PRINT "hello world!"
' ------------------------------------------
  abc = 11100
  xyz = 32000
  abc% = 33000
  xyz% = 99000
  abc! = 33000.33
  xyz! = 99000.47
  abc# = 333000.33
  xyz# = 999000.47
  test$ = "test"
'
  CLEAR abc, xyz, INT, abc%, xyz%, LNG, abc!, xyz!, FLT
  CLEAR abc#, xyz#, DBL, test$, STR
  CLEAR
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

NUMERICAL DATA TYPES:
**NOTE: Bxbasm is a strongly typed language. That means that data types must be indicated by the use of a data-type specifier at the end of each variable name. If no data type specifier is appended to a variable, then Bxbasic will assume the default data type of Integer.

Bxbasm uses four (4) numeric data types:
data type:		symbol:	example:
Integer		   %		ivariable% = 99
Long Integer	   @		lvariable@ = 987654321
Float			   !		fvariable! = 1.123456
Double Float	   #		dvariable# = 123.123456789

Simple integers have a limited range and can not handle fractional or "real" numbers. As shown here, an expression may contain mixed data types. The result will be the destination variable's type.

'  test.bas version 14
Start1:
  CLS
  PRINT "hello world!"
' ------------
  LET xylophone# = 50.3
  LET yazoo# = 101.25
  LET abc = yazoo#/xylophone#
  xyz = yazoo#/10
  LOCATE abc , xyz
  PRINT "hello world!"
' ------------------------------------------
  quasar = 2
  zapp = 4
  abc = (quasar * quasar * zapp + zapp)/5
  xyz = ((quasar * quasar) * zapp) + zapp
  LOCATE abc, xyz
  PRINT "hello world!"
' ------------------------------------------
  PRINT
  PRINT " 2*(3+4)*5/10 = ";
  abc = 2*(3+4)*5/10
  PRINT abc
' ------------------------------------------
  PRINT
  PRINT "xylophone# = ";
  PRINT xylophone#
  PRINT "yazoo# = ";
  PRINT yazoo#
TheEnd:
  CLEAR
  END
' ------------------------------------------

Here are some examples of expressions using different data types.

'  test.bas version 15
Start1:
  CLS
  PRINT "hello world!"
' ------------------------------------------double float
  LET xylophone# = 50.3
  LET yazoo# = 101.25
  LET abc = yazoo#/xylophone#
  xyz = yazoo#/10
  LOCATE abc , xyz
  PRINT "hello world!"
' ------------------------------------------long integers
  quasar% = 2
  zapp% = 4
  abc% = (quasar% * quasar% * zapp% + zapp%)/5
  xyz% = ((quasar% * quasar%) * zapp%) + zapp%
  LOCATE abc%, xyz%
  PRINT "hello world!"
' ------------------------------------------
  PRINT
  PRINT " 2*(3+4)*5/10 = ";
  abc = 2*(3+4)*5/10
  PRINT abc
' ------------------------------------------
  PRINT
  PRINT "xylophone# = ";
  PRINT xylophone#
  PRINT "yazoo# = ";
  PRINT yazoo#
  PRINT
  PRINT "abc%=";
  PRINT abc%
  PRINT "xyz%=";
  PRINT xyz%
' ------------------------------------------
TheEnd:
  CLEAR
  END
' ------------------------------------------

'  test.bas version 16
Start1:
  CLS
' ------------------------------------------
  abc = 11100
  xyz = 32000
  abc% = 33000
  xyz% = 99000
  abc! = 33000.33
  xyz! = 99000.47
  abc# = 333000.33
  xyz# = 999000.47
'                   integer
  PRINT
  PRINT "abc=";
  PRINT abc
  PRINT "xyz=";
  PRINT xyz
'                   long
  PRINT "abc%=";
  PRINT abc%
  PRINT "xyz%=";
  PRINT xyz%
'                   float
  PRINT "abc!=";
  PRINT abc!
  PRINT "xyz!=";
  PRINT xyz!
'                   double
  PRINT "abc#=";
  PRINT abc#
  PRINT "xyz#=";
  PRINT xyz#
' ------------------------------------------
TheEnd:
  CLEAR
  END
' ------------------------------------------

'  test.bas version 17
Start1:
  CLS
  PRINT "hello world!"
' ------------------------------------------double float
  LET xylophone# = 50.3
  LET yazoo# = 101.25
  LET abc = yazoo#/xylophone#
  xyz = yazoo#/10
  LOCATE abc , xyz
  PRINT "hello world!"
' ------------------------------------------long integers
  quasar% = 2
  zapp% = 4
  abc% = (quasar% * quasar% * zapp% + zapp%)/5
  xyz% = ((quasar% * quasar%) * zapp%) + zapp%
  LOCATE abc%, xyz%
  PRINT "hello world!"
' ------------------------------------------
  PRINT
  PRINT " 2*(3+4)*5/10 = ";
  abc = 2*(3+4)*5/10
  PRINT abc
' ------------------------------------------
  abc = 11100
  xyz = 32000
  abc% = 33000
  xyz% = 99000
  abc! = 33000.33
  xyz! = 99000.47
  abc# = 333000.33
  xyz# = 999000.47
'                   integers
  PRINT
  PRINT "abc=";
  PRINT abc
  PRINT "xyz=";
  PRINT xyz
'                   long integers
  PRINT "abc%=";
  PRINT abc%
  PRINT "xyz%=";
  PRINT xyz%
'                   float
  PRINT "abc!=";
  PRINT abc!
  PRINT "xyz!=";
  PRINT xyz!

'                   double
  PRINT "abc#=";
  PRINT abc#
  PRINT "xyz#=";
  PRINT xyz#
' ------------------------------------------
TheEnd:
  CLEAR
  END
' ------------------------------------------

STRING VARIABLES:
String variable assignments may be expressed in several ways.
To begin with, a string variable is terminated by the '$' symbol. A string variable may be a single character, no character, or a number of characters, with a maximum of 255 characters.

'  test.bas version 18
Start1:
  CLS
  PRINT "hello world!"
  abc$ = "test"
  xyz$ = ""
'   ^---------------here, xyz is null, empty!
  END
'-------------------------

'  test.bas version 19
  CLS
  abc$ = "testing"
  xyz$ = abc$
  PRINT abc$
  PRINT xyz$
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

COMPLEX PRINTING:
The PRINT statement can be used in complex ways to create the desired display.

'  test.bas version 20
Start1:
  CLS
  PRINT "hello world!"
' ------------------------------------------
  abc = 2*(3+4)*5/10
  PRINT
  PRINT " 2*(3+4)*5/10 = "; abc
  PRINT
' ------------------------------------------
  abc = 11100
  xyz = 32000
  abc% = 33000
  xyz% = 99000
  abc! = 33000.33
  xyz! = 99000.47
  abc# = 333000.33
  xyz# = 999000.47
'                   				integers
  PRINT "abc="; abc, "xyz="; xyz
'                   				long integers
  PRINT "abc%="; abc%, "xyz%="; xyz%
'                   				float
  PRINT "abc!="; abc!, "xyz!="; xyz!
'                   				double
  PRINT "abc#="; abc#, "xyz#="; xyz#
' ------------------------------------------
TheEnd:
  CLEAR
  END
' ------------------------------------------

GOSUB RETURN:
Subroutines are the preferred method of program branching. Subroutines allow for a more structured style of programming over the absolute jump of a GOTO statement.
Subroutines are identified by a block label and called with the GOSUB command.
Each GOSUB command has a matching RETURN command. If you GOSUB, you must RETURN from the subroutine.

'  test.bas version 21
  GOSUB Start1
  GOSUB DoubleFloat
  GOSUB LongIntegers
  GOSUB RDParser
  GOSUB PrintVars
  GOSUB ClearVars
  GOTO TheEnd
' ------------------------------------------
Start1:
  CLS
  Hello$ = "hello world!"
  PRINT Hello$
  RETURN
' ------------------------------------------double float
DoubleFloat:
  LET xylophone# = 50.3
  LET yazoo# = 101.25
  LET abc = yazoo#/xylophone#
  xyz = yazoo#/10
  LOCATE abc , xyz
  PRINT Hello$
  RETURN
' ------------------------------------------long integers
LongIntegers:
  quasar% = 2
  zapp% = 4
  abc% = (quasar% * quasar% * zapp% + zapp%)/5
  xyz% = ((quasar% * quasar%) * zapp%) + zapp%
  LOCATE abc%, xyz%
  PRINT Hello$
  RETURN
' ------------------------------------------
RDParser:
  abc = 2*(3+4)*5/10
  PRINT
  PRINT " 2*(3+4)*5/10 = "; abc
  PRINT
  RETURN
' ------------------------------------------

PrintVars:
  abc = 11100
  xyz = 32000
  abc% = 33000
  xyz% = 99000
  abc! = 33000.33
  xyz! = 99000.47
  abc# = 333000.33
  xyz# = 999000.47
'                   			integers
  PRINT "abc="; abc, "xyz="; xyz
'                   			long integers
  PRINT "abc%="; abc%, "xyz%="; xyz%
'                   			float
  PRINT "abc!="; abc!, "xyz!="; xyz!
'                   			double
  PRINT "abc#="; abc#, "xyz#="; xyz#
  RETURN
' ------------------------------------------
ClearVars:
  test$ = "test"
  CLEAR abc, xyz, INT, abc%, xyz%, LNG, abc!, xyz!, FLT
  CLEAR abc#, xyz#, DBL, test$, STR
  CLEAR
  RETURN
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

GOSUB's may be nested. That means that a second GOSUB may be called even before RETURNing from the first subroutine. The second subroutine may even call a third subroutine, etc. As long as there are an equal number of RETURNs as GOSUBs.

'  test.bas version 22
  GOSUB Start1
  GOTO TheEnd
' ------------------------------------------
Start1:
  CLS
  Hello$ = "hello world!"
  PRINT Hello$
  GOSUB DoubleFloat
  RETURN
' ------------------------------------------double float
DoubleFloat:
  LET xylophone# = 50.3
  LET yazoo# = 101.25
  LET abc = yazoo#/xylophone#
  xyz = yazoo#/10
  LOCATE abc , xyz
  PRINT Hello$
  GOSUB LongIntegers
  RETURN
' ------------------------------------------long integers
LongIntegers:
  quasar% = 2
  zapp% = 4
  abc% = (quasar% * quasar% * zapp% + zapp%)/5
  xyz% = ((quasar% * quasar%) * zapp%) + zapp%
  LOCATE abc%, xyz%
  PRINT Hello$
  GOSUB RDParser
  RETURN
' ------------------------------------------
RDParser:
  abc = 2*(3+4)*5/10
  PRINT
  PRINT " 2*(3+4)*5/10 = "; abc
  PRINT
  GOSUB PrintVars
  RETURN
' ------------------------------------------

PrintVars:
  abc = 11100
  xyz = 32000
  abc% = 33000
  xyz% = 99000
  abc! = 33000.33
  xyz! = 99000.47
  abc# = 333000.33
  xyz# = 999000.47
'                   			integers
  PRINT "abc="; abc, "xyz="; xyz
'                   			long integers
  PRINT "abc%="; abc%, "xyz%="; xyz%
'                   			float
  PRINT "abc!="; abc!, "xyz!="; xyz!
'                   			double
  PRINT "abc#="; abc#, "xyz#="; xyz#
  GOSUB ClearVars
  RETURN
' ------------------------------------------
ClearVars:
  test$ = "test"
  CLEAR abc, xyz, INT, abc%, xyz%, LNG, abc!, xyz!, FLT
  CLEAR abc#, xyz#, DBL, test$, STR
  CLEAR
  RETURN
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

FOR NEXT:
The FOR/NEXT commands allow for the creation of complex loop structures.
The basic syntax is:
		FOR (condition, increment)
			program...
		NEXT (increment loop)

The 'conditional expression' and 'increment' take the form of:
		variable% = start TO end, STEP increment

     variable%:  is the object of the condition
         start:  is the starting value for 'variable'
           end:  is the destination for 'variable'
     increment:  is the amount by which to increment 'variable'

Where:	FOR x% = 1 TO 100 STEP 1

   x% = 1:   Assigns the starting value of 1 to variable 'x%'.
             Variable 'x' must be of type: LONG: (%).
   TO 100:   Sets a desired value of: 100 for 'x'.
   STEP 1:   The amount by which to increment.
             If the STEP value were: 3
             'x%' would be incremented by 3 after each loop cycle.
             If no STEP value is stated, the default is: 1.

NEXT is little more than a block label, or block delimiter, but, it also keeps track of which variable we need to increment for the next cycle.

FOR/NEXTs may be nested. 
i.e.:		FOR (cond-1)		[outer loop]
			FOR (cond-2)	[inner loop]
				program...
			NEXT (inc)		[inner loop]
		NEXT (inc)			[outer loop]

However, you may not exit an outer loop before exiting an inner loop. An inner loop may be terminated, however. 
To terminate an inner loop, an IF/ELSE expression can be used to test for a condition and based on the result, object variable can be forced to the destination value. Example:

		FOR x% = 1 TO 10
		    FOR y% = 1 TO 100	......[inner loop]
		        IF y% = 50 THEN
			      y% = 100		[force: y% = 100]
			  ENDIF
			  PRINT CHR$(32);
		    NEXT y%			......[inner loop]
		NEXT x%

This will have the desired effect of satisfying the condition:
		    FOR y% = 1 TO 100

'  test.bas version 23
  CLS
  GOSUB TOP
  GOSUB Center
  GOSUB Bottom
  GOTO TheEnd
'----------------------
Center:
  FOR x% = 1 TO 5
      PRINT "*";
      FOR y% = 1 TO 28
          PRINT " ";
      NEXT y%
      PRINT "*"
  NEXT x%
  RETURN
'----------------------
TOP:
Bottom:
  FOR x% = 1 TO 30
      PRINT "*";
  NEXT x%
  PRINT ""
  RETURN
'----------------------
TheEnd:
  END
'----------------------

This example will generate a box made of stars in the upper left corner of the display, like this:

******************************
*                            *
*                            *
*                            *
*                            *
*                            *
******************************

POWER, MODULUS:
Besides the numerical operators: +,-,/ and *, Bxbasic also uses the Power symbol: ^ and the Modulo symbol: %. 
Power:
The symbol ^ represents the Power function. The effect is to raise a number to the Power of a second number. 
Example:
	result = 10 ^ 2	"result" equals: 10 raised to the power of 2.
				The product, (100) is assigned to "result"

Modulo:
The symbol % represents the Modulus function. The effect is to capture the remainder of a division operation. 
Example:
	mod = 10 % 3	"mod" equals the remainder of 10/3.
				The product, (1) is assigned to variable "mod"

'  test.bas version 24
  GOSUB Start1
  END
' ------------------------------------------
Start1:
  CLS
  power = 10 ^ 2
  PRINT "power="; power
'
  ten = 10
  three = 3
'                we can use the modulus operator: %
  mod = ten % three
  PRINT "mod="; mod
'                or we can use the keyword: MOD 
  mod = 30 MOD 9
  mod = ten MOD mod
  PRINT "mod="; mod
  RETURN
' ------------------------------------------

The word MOD may be used in place of the % symbol.
One word of caution: when used with numeric variables, the % symbol has to have a blank space on either side of it, or the variable may be confused as a LONG integer. 
i.e.: 	var1 % var2 	correct.
		var1%var2		incorrect!

IF/ELSE:
The IF/ELSE conditional expression uses the form:
	IF (condition) THEN		first condition
		[program...]
	ELSEIF (condition) THEN		second condition
		[program...]
	ELSE					default action
		[program...]
	ENDIF					terminator

In the above, there are two conditional expressions:
Condition #1:
	if condition #1 is TRUE, then:
		[the following action is taken]
		[program resumes at point beyond the ENDIF]
	if condition #1 is FALSE, then:
		[evaluate expression #2]
	--------------------------------------
Condition #2:
	elseif condition #2 is TRUE, then:
		[the following action is taken]
		[program resumes at point beyond the ENDIF]
	elseif condition #2 is FALSE, then:
		[take default action]
	--------------------------------------
Default:
	else
		[the following action is taken]
		[program resumes at point beyond the ENDIF]
	endif

The simplest conditional expression might be:
	IF (condition) THEN		conditional expression
		[program...]
	ENDIF					terminator

where only one condition is evaluated.
Conditional expressions may also use the Boolean AND/OR operators.
Example:
		IF a = b AND x = y THEN
		...etc.
or:
		IF a = b OR x = y THEN
		...etc.

These condition operators may be used:
	   operator		description
		=		is equal to
		<>		is not equal to
		<		is less than
		>		is greater than
		<=		is less or equal to
		>=		is greater or equal to

'  test.bas version 25
  CLS
  abc = 99
  xyz = 33
  abc$ = "test"
  xyz$ = "testing"
'
  IF xyz$ = "testing" AND abc >= xyz THEN 
     PRINT "if:expression = true"
  ELSEIF abc <= 100 OR abc$ <= "hello" THEN
     PRINT "elseif:expression = true"
  ELSE
     PRINT "else:expressions = false"
  ENDIF
  PRINT "done"
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

STRING FUNCTIONS:
	Function:	Usage:
	CHR$()	a$ = CHR$(n)
					where: (n) is an ascii value.

	LEFT$()	a$ = LEFT$(s$,n)
					where: s$ is a string variable name,
					'n' is the number of characters to copy
					from the left.

	RIGHT$()	a$ = RIGHT$(s$,n)
					where: s$ is a string variable name,
					'n' is the number of characters to copy
					from the right.

	MID$()	a$ = MID$(s$,x,n)
					where: s$ is a string variable name,
					'x' is the character starting position
					from the left,
					'n' is the number of characters to copy.

	SPACE$()	a$ = SPACE$(n)
					where: 'n' is the number of blank spaces

	STR$()	a$ = STR$(n)
					where: 'n' is a numeric value to be 
					converted to a character string.

	STRING$()	a$ = STRING$(n,x)
					where: 'n' is the number of characters,
					'x' is an ascii value.

'  test.bas version 26
  CLS
  xyz = 42
  abc$ = CHR$(xyz)
  PRINT "abc$ = ";abc$
'
  xyz$ = "testing"
  abc$ = LEFT$(xyz$, 4)
  PRINT abc$
'
  abc$ = RIGHT$(xyz$, 5)
  PRINT abc$
'
  abc$ = MID$(xyz$, 3, 3)
  PRINT abc$
'
  abc$ = SPACE$(3)
  PRINT ">";abc$;"<"
'
  abc$ = STR$(199)
  PRINT abc$
'
  abc$ = STRING$(10, xyz)
  PRINT ">";abc$;"<"
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

'  test.bas version 27
  CLS
  xyz = 42
  xyz$ = "testing"
'
  abc$ = LEFT$(xyz$, 4) + CHR$(xyz) + RIGHT$(xyz$, 5) + SPACE$(3) + MID$(xyz$, 3, 3) + STR$(-199) + STRING$(10, xyz)
  PRINT abc$
'
  abc$ = CHR$(34) + "Hello" + CHR$(32) + "world!" + CHR$(34)
  PRINT abc$
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

'  test.bas version 28
  CLS
  abc$ = "This is a test of the Emergency Broadcast System"
  PRINT "Test: >"; CHR$(251); "< End Test"
  PRINT ">"; LEFT$(abc$, 14); "<"
  PRINT ">"; RIGHT$(abc$, 26); "<"
  PRINT ">"; MID$(abc$, 23, 19); "<"
  PRINT ">"; SPACE$(10); "<"
  PRINT ">"; STR$(1000); "<"
  PRINT ">"; STRING$(10, 251); "<"
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

'  test.bas version 29
  CLS
  PRINT ">"; STR$(1000); "<"
  PRINT ">"; STRING$(10, 251); "<"
  PRINT CHR$(247)
  abc = 10
  xyz = 3
  PRINT abc * xyz
  PRINT 1 + (abc * xyz)
  PRINT (abc / xyz) * 2
  PRINT 1+(2*5)/3
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

INKEY$:
The INKEY$ function captures the character currently entered in the keyboard buffer. INKEY$ has a unique quality that makes it quite different from other types of keyboard input. When INKEY$ is called, it does not wait for the user to strike a key. Instead, after collecting the character, even if there is no character in the buffer, it continues on to the next instruction. 
You may be wondering what good is that?
I doesn't wait for you to type a character?

The short answer is no, it doesn't wait.
On the other hand the user doesn't have to strike the return key, either.
What does this mean?

INKEY$ is especially well suited for a loop construct or a subroutine call that polls the keyboard buffer.

Here is an example of how to use INKEY$:

'  test.bas version 30
  CLS
Start:
  abc$ = INKEY$
  IF abc$ = "" THEN
    GOTO Start
  ENDIF
  PRINT abc$
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

In the above example, INKEY$ is used in a continuous loop, that tests the keyboard buffer for a character. If there is no character, then abc$ will be null, or empty. In that event, program control jumps back up to Start: and repeats the loop.
Does this look familiar?
		Press any key to continue._

'  test.bas version 31
  CLS
  PRINT "Press any key: ";
Start:
  abc$ = INKEY$
  IF abc$ = "" THEN
    GOTO Start
  ENDIF
  PRINT abc$
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

INPUT:
The INPUT command accepts standard input from the keyboard. The INPUT command requires a return or newline character to terminate input.
Example:
		INPUT a$		accepts a character string
		INPUT val		accepts a numeric value

In this example:
	INPUT ;"First: "; first$; " Last: "; last$:

the display shows:
	First: _

while the cursor waits for the contents of first$ to be entered.
Which then displays:
	First: Bill Last:_

on the same line, waiting for the contents of last$ to be entered.
INPUT, in this example, acts as both an INPUT and a PRINT command. Since the return key is required to end input, by placing a semi-colon after the INPUT command, tells Bxbasic not to echo the newline character.
Example:
		INPUT ; "Enter your Name: "; name$

This will have the effect of keeping the cursor on the same line.

'  test.bas version 32
  CLS
  PRINT "Press any key to begin: ";
Start:
  abc$ = INKEY$
  IF abc$ = "" THEN
    GOTO Start
  ENDIF
  PRINT abc$
'
  PRINT "Enter your name:"
  INPUT ;"First: "; first$; " Initial: "; init$; " Last: "; last$
  PRINT "Enter your age and birth date:"
  INPUT ;"Age: "; age; " Month: "; mo; "/Day: "; day; "/Year: "; year%
'
  PRINT first$, init$, last$
  PRINT age, mo, day, year%
  INPUT a$
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

INPUT$:
The INPUT$ function differs from the INPUT command in the way in which it is used. The INPUT$ function is a character string function and is used to input string data, as opposed to numeric data. The characters entered are assigned to a string variable. The INPUT$ function accepts a parameter, in the form of an integer value. That value is the number of characters that INPUT$ will accept. 
Example:
		a$ = INPUT$(n)	where 'n' is an integer

Once the total number of characters have been entered, the program moves on to the next instruction. Hitting the return key is not required, but, entering the total number of characters is.
An example of where this might be used is in accepting data entry of a known fixed length.

'  test.bas version 33
  CLS
  abc$ = INPUT$(10)
  PRINT abc$
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

LINE INPUT:
The LINE INPUT command is very similar to the plain INPUT command, except that all the data entered is assigned to a single string variable. Also,  LINE INPUT will accept an entire line of text, up to 255 characters and is terminated by a newline character. LINE INPUT can be used much the same way as the INPUT command, with or without a prompt string:
Example:
	LINE INPUT "Enter your: Address, City and State: "; a$
or	LINE INPUT a$

The return key terminates input.

'  test.bas version 34
  CLS
  PRINT "1: ";
  LINE INPUT abc$
'           ^-----notice no prompt
  PRINT abc$
  LINE INPUT "2:enter a string: "; abc$
  PRINT abc$
  LINE INPUT ;"3:enter a string: "; abc$
'            ^------no echo:return
  PRINT abc$
  LINE INPUT ;"4:enter a string: "; abc$,
'  no echo---^         insert tab-------^
  PRINT abc$
  INPUT a$
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

ALGEBRAIC FUNCTIONS:
	Function:	Usage:
	ABS(n)	num% = ABS(number)
				returns the absolute value of a number.

	ASC(c$)	num = ASC(char$)
				returns the value of an ascii character.

	ATN(n)	num# = ATN(num)
				returns the arctangent of a number.

	COS(n)	num# = COS(num)
				returns the cosine of a number.

	SIN(n)	num# = SIN(num)
				returns the sine of a number.

	TAN(n)	num# = TAN(num)
				returns the tangent of a number.

	SQRT(n)	num# = SQRT(num)
				returns the square root of a number.

	INT(n)	num% = INT(num#)
				returns the integer value of a floating point
				number.

'  test.bas version 35
  CLS
  xyz = 99
  abc = ABS(xyz - 1.75)
  PRINT abc
  abc = ASC("A")
  PRINT abc
  abc! = ATN(xyz / 3)
  PRINT abc!
  abc! = COS(5.8 * .0174533)
  PRINT abc!
  abc! = SIN(xyz / 11)
  PRINT abc!
  abc! = TAN(xyz / 10)
  PRINT abc!
  abc! = SQRT(xyz)
  PRINT abc!
  abc = INT(xyz / 3.1)
  PRINT abc
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

'  test.bas version 36
  CLS
  abc = 10
  xyz = 99
  PRINT ABS(xyz - 1.75)
  PRINT ASC("A")
  PRINT ATN(xyz / 3)
  PRINT COS(5.8 * .0174533)
  PRINT SIN(xyz / 11)
  PRINT TAN(xyz / 10)
  PRINT SQRT(xyz)
  PRINT INT(xyz / 3.1)
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

DISK FILE I/O:
OPEN, CLOSE:
File I/O is dependant on the abiliy to OPEN and CLOSE disk files. The OPEN command requires a specific format using three parameters.
i.e.:		1) I/O Mode
		2) File Handle
		3) Filename/Path
Example:
		OPEN "I", #1, "data.fil"
    I/O Mode------^    ^      ^-------Filename
		           ^-----File Handle

The I/O Modes are:
		I = Input		read a file
		O = Output		create/write to file
		A = Append		write to existing file

File Handle numbers can range from 1 to 99.
The CLOSE command can be used in two ways:
		CLOSE			close all open files
		CLOSE 1,2,3		close files #1, #2 and #3

Before we can run this next program, you will need to create a file named Test.txt. Using Notepad, create an empty file,  just hit the return key about three or four times, then save the file to your working directory, naming it "Test.txt", and close it.
Now copy this to Test.bas, then compile and run it:

'  test.bas version 37
  CLS
'
  PRINT "Opening Test File"
  OPEN "I", #1, "test.txt"
  PRINT "Closing Test File"
  CLOSE 1
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

Okay, maybe that wasn't all that impressive, but, it did OPEN Test.txt for Input and then CLOSE it.

In this next example, a character string, filename$, is assigned the file-name information. Either a quoted string, as used in the above, or a string variable may be used for this purpose.

'  test.bas version 38
  CLS
  filename$ = "test.txt"
  '
  PRINT "Opening Test File"
  OPEN "I", #1, filename$
  PRINT "Closing Test File"
  CLOSE 1
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

For the next example, copy this line of data to our data file, Test.txt:

hello world,next string,32000,650000,1.123,3000000.123

Make sure this is at the very top line. Also, delete any blank lines that may come after it, so that this is the only thing in Test.txt.
Now, compile and run this Test.bas:

'  test.bas version 39
  CLS
'
  PRINT "Opening Test File"
  OPEN "I", #1, "test.txt"
  INPUT#1, input$, next$, valuea, valueb%, valuec!, valued#
  CLOSE 1
  PRINT input$, next$, valuea, valueb%, valuec!, valued#
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

When executed, Bxbasic OPENs Test.txt for Input, using Handle #1 and INPUTs two string variables and four numeric variables. It then CLOSEs Handle #1 and prints out the information.

Now, let's try something a little more challenging. Copy the following into the data file: Test.txt

hello world,next string,32000,650000,1.123,3000000.123
hello ,world,2000,50000,0.123,5000000.123

Now compile and run this Test.bas:

'  test.bas version 40
  CLS
'
  PRINT "Opening Test File"
  OPEN "I", #1, "test.txt"
  INPUT#1, input$, next$, valuea, valueb%, valuec!, valued#
  PRINT input$, next$, valuea, valueb%, valuec!, valued#
'
  INPUT#1, input$, next$, valuea, valueb%, valuec!, valued#
  PRINT input$, next$, valuea, valueb%, valuec!, valued#
  CLOSE 1
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

In this example, Bxbasic reads in two seperate lines of data and processed it as before.
This is okay, if you only have one or two lines of data to input. In practice, though, it's not very practical.

EOF():
If you have a data file that contains twenty lines of data to input, you don't want to code twenty identical lines of INPUT instructions. Instead, a more practical application would be to read the data in, in some form of loop. For example:

  OPEN "I", #1, "test.txt"
'
Start:
  INPUT#1, input$, next$, valuea, valueb%, valuec!, valued#
  PRINT input$, next$, valuea, valueb%, valuec!, valued#
  GOTO Start
  ...

Here, the program loops through the data file, inputing each line of data. There is one major problem with this though. The code above forms a continuous loop that would end in an error or program crash.
Why ?
It has to do with the fact that when the program gets to the end of the file, it just tries to keep on reading. This is not a good thing. The solution is to have a means of detecting when we have reached the end of the file and terminate the process before it does any harm. That is where EOF comes in.

EOF is a file or device function. The sole purpose is to detect the End-Of-File. Using the sample code from above, all we need to do is to add a condition test to the loop, that will test for End-Of-File. 
Like this:
  OPEN "I", #1, "test.txt"
'
Start:
  IF EOF(1) THEN
     GOTO Finish
  ENDIF
  INPUT#1, input$, next$, valuea, valueb%, valuec!, valued#
  PRINT input$, next$, valuea, valueb%, valuec!, valued#
  GOTO Start
Finish:
  CLOSE 1

In this example, we keep looping, reading-in data, until we detect an End-Of-File condition. Then we stop trying to read.

Below, is a Test.bas that we can try it on. Before we can test this out, we need to modify Test.txt. Copy the following into Test.txt:

hello world,next string,32000,650000,1.123,3000000.123
hello ,world,2000,50000,0.123,5000000.123
hello world,next string,32000,650000,1.123,3000000.123

Save and close it. 
Now compile this:

'  test.bas version 41
  CLS
  PRINT "Opening Test File"
  OPEN "I", #1, "test.txt"
'
Start:
  IF EOF(1) THEN
     GOTO Finish
  ENDIF
  INPUT#1, input$, next$, valuea, valueb%, valuec!, valued#
'
  IF input$="" THEN
     GOTO Start
  ENDIF
  PRINT input$, next$, valuea, valueb%, valuec!, valued#
  GOTO Start
'
Finish:
  CLOSE 1
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

In line 12, is another status test. There, it is testing for the possibility of a mis-read, where a read attempt was made but for some reason it was unable to. In this case, it loops back up to see if it has reached the End-Of-File.

WRITE:
Inputing data is only half of file I/O. The other half is WRITEing data to a disk file. The WRITE command looks identical to the INPUT command. In fact, the WRITE command is the mirror image of the INPUT command. Except that the data flows in the opposite direction.

Here is an example where we open a second file for OUTPUT and WRITE to it the data we have INPUT from the first file. Notice that the data written out need not be in the same order as was read-in.

'  test.bas version 42
  CLS
'
  PRINT "Opening Test File"
  OPEN "I", #1, "test.txt"
'
  OPEN "O", #2, "test2.txt"
'
Start:
  IF EOF(1) THEN
     GOTO Finish
  ENDIF
  INPUT#1, input$, next$, valuea, valueb%, valuec!, valued#
  IF input$="" THEN
     GOTO Start
  ENDIF
  PRINT input$, next$, valuea, valueb%, valuec!, valued#
'
  WRITE#2, valued#, valuec!, valueb%, valuea, next$, input$
' ..................write data in reversed order!
  GOTO Start
'
Finish:
  CLOSE 1, 2
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

Compile and execute the above Test.bas
and then examine the contents of Test2.txt.

Now try this next one:

'  test.bas version 43
  CLS
'
  PRINT "Opening Test File"
  OPEN "I", #1, "test.txt"
'
  OPEN "A", #2, "test2.txt"
'
Start:
  IF EOF(1) THEN
     GOTO Finish
  ENDIF
  INPUT#1, input$, next$, valuea, valueb%, valuec!, valued#
  IF input$="" THEN
     GOTO Start
  ENDIF
  PRINT input$, next$, valuea, valueb%, valuec!, valued#
  WRITE#2, input$, next$, valuea, valueb%, valuec!, valued#
  GOTO Start
'
Finish:
  CLOSE 1, 2
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

Is there going to be anything different in the result ?
After executing it, examine Test2.txt.

LINE INPUT#:
Just as we can use the LINE INPUT command to enter an entire line of text from the keyboard, we can also us it to INPUT an entire line of data from a disk file.
An entire line of data, up to 255 characters, terminated by a newline character, can be read in to a single string variable.

Now try this Test.bas:

'  test.bas version 44
  CLS
'
  PRINT "Opening Test File"
  OPEN "I", #1, "test.txt"
'
Start:
  IF EOF(1) THEN
     GOTO Finish
  ENDIF
  LINE INPUT#1, input$
'
  IF input$="" THEN
     GOTO Start
  ENDIF
  PRINT input$
  GOTO Start
'
Finish:
  CLOSE 1
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

PRINT#:
The function that mirrors LINE INPUT, oddly enough is not LINE WRITE, but, PRINT#. We are using the PRINT command and the hash-mark (#) indicates that we are PRINTing to a device.
Try this Test.bas and then examine Test2.txt:

'  test.bas version 45
  CLS
'
  PRINT "Opening Test File"
  OPEN "I", #1, "test.txt"
  OPEN "O", #2, "test2.txt"
'
Start:
  IF EOF(1) THEN
     GOTO Finish
  ENDIF
  LINE INPUT#1, input$
'
  IF input$="" THEN
     GOTO Start
  ENDIF
  PRINT input$
  PRINT#2, input$
  GOTO Start
'
Finish:
  CLOSE 1, 2
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

RANDOM I/O
An additional method of disk I/O is called Random Access. Unlike sequential file access, which requires that disk file data be accessed sequentially, from beginning to end, Random access allows individual records to be written or read from a disk file in any desired order. Generally, in a random access file, records have a fixed length, with a predetermined number of characters or bytes. There by allowing records to be stored with each record having a known distance from the beginning of the file. 

For instance, assume for a moment that a database will contain an unknown number of records, but, that each record will have a fixed length of one hundred ascii characters. 
Example:
      first name:[               ] = 15 characters
       last name:[               ] = 15 characters
         address:[                              ] = 30 characters
     information:[                    ] = 20 characters
     information:[                    ] = 20 characters

The record consists of the clients: name, address and information, for a 
total of 100 characters.
If this record were to be stored as record number one, then record number two would be stored beginning one hundred bytes away from the beginning of the file. You would say that record number two has an offset of one hundred bytes. Record number three would begin two hundred bytes from the start of the file and therefore have an offset of two hundred bytes.

A disk file of this description, opened for random access, would have the ability to read-in or write-out data using a disk buffer one hundred bytes in length. Reading in or writing out information one hundred bytes at a time, beginning at a calculated offset for a particular record.

Since a random access file has the ability to read or write individual records without disturbing the surrounding records, it need not be opened strictly for INPUT or for OUTPUT. Once a random access file is opened, it may be both read from and written to, at the same time.

Opening a random access file is no different from opening a sequential access file, with the exception that an "R" is used for the mode specifier and the filename/path is followed by the record length. 
i.e.:
    OPEN "R", #1, "test.txt", 50

The record length indicates the number of bytes the buffer will read or write for each record and will be used to calculate the offsets for each record.
There are five commands that are used when dealing with random access files: FIELD, LSET, RSET, PUT and GET.

FIELD: divides the I/O buffer into it's individual parts or strings of information that will comprise the record. Using the above example data:

	      first name: = 15 characters
	       last name: = 15 characters
	         address: = 30 characters
	     information: = 20 characters
	     information: = 20 characters

the I/O buffer will be divided up like this:
			I/O BUFFER
  [first$    ][last$     ][address$  ][info1$    ][info2$    ]
  ( 15 chars )( 15 chars )( 30 chars )( 20 chars )( 20 chars )

The usage for the FIELD command is:
	FIELD #1, 15 AS F$, 15 AS L$, 30 AS A$, 20 AS I1$, (etc...)

LSET/RSET: are abbreviations for Left-Set and Right-Set. 
In the event that the data contained in a particular string is too short, for instance if first$ only contains five characters and not all fifteen, LSET or RSET may be used to add padding, (blank spaces) to fill in the required length. 
The difference between LSET and RSET is that:
LSET pushes the existing string information to the far left of the string and adds any required padding to the right of the data. 
RSET pushes the existing string information to the far right of the string and adds any required padding to the left of the data.
Example:
		First$ = "Fred"
		LSET [Fred...........]
		RSET [...........Fred]

LSET and RSET guarantee that each data string is the proper length when put into the buffer before writing it to the file.

Usage for LSET and RSET are:
		LSET F$ = first$
		LSET L$ = last$
		LSET A$ = address$
		RSET I1$ = info1$
		RSET I2$ = info2$

As a result of the LSET or RSET commands, the data is set to the proper lengths and placed into the I/O buffer.
	
PUT: is the command to write the buffer to the file.
The usage is:
		PUT 1,(record #)
		PUT 1, 99
		PUT 1, rec%   (where rec% is a long integer variable)

GET: is the command to read-in a file record into the buffer.
Usage is:
		GET 1,(record #)
		GET 1, 99
		GET 1, rec%   (where rec% is a long integer variable)

Here is an example of using the above random access commands:
**(first, begin by deleteing "Test.txt"):

'  test.bas version 46
    CLS
    '
    q$ = "This"
    x$ = "is"
    y$ = "a"
    z$ = "test"
    w$ = "record"
'
    OPEN "R", #1, "test.txt", 50
    FIELD #1, 10 AS A$, 10 AS B$, 10 AS C$, 10 AS D$, 10 AS E$
    LSET A$ = q$
    LSET B$ = x$
    LSET C$ = y$
    LSET D$ = z$
    RSET E$ = w$
    PUT 1, 1
    CLOSE 1
    PRINT "Done!"
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

Cut-n-paste Test.bas #46 and try it, then examine file: "test.txt".
Now, still using #46, change the record number in the PUT statement to read:
	PUT 1, 2

then re-compile Test.bas and after you run it, examine "test.txt".

Now try this Test.bas:

'  test.bas version 47
    CLS
    '
    q$ = "This"
    x$ = "is"
    y$ = "a"
    z$ = "test"
    w$ = "record"
    rec% = 1
'
    OPEN "R", #1, "test.txt", 50
    FIELD #1, 10 AS A$, 10 AS B$, 10 AS C$, 10 AS D$, 10 AS E$
    FOR x% = 1 TO 5 STEP 1
        LSET A$ = q$
        LSET B$ = x$
        LSET C$ = y$
        LSET D$ = z$
        RSET E$ = w$
        '
        PUT 1, rec%
        rec% = rec% + 1
    NEXT x%
    CLOSE 1
    CLEAR
'
    OPEN "R", #1, "test.txt", 50
    FIELD  1, 10 AS A$, 10 AS B$, 10 AS C$, 10 AS D$, 10 AS E$
    GET 1, 2
'
    PRINT A$
    PRINT B$
    PRINT C$
    PRINT D$
    PRINT E$
    CLOSE 1

' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

I/O STRING FUNCTIONS:
As you've seen in the above, when reading from or writing to a random I/O file, the buffer is made up of fixed length strings. You may be wondering how then do we read or write numeric information, such as floating point numbers or the results of a calculation. This is accomplished with the "make" and "convert" functions.
The make functions are:
			MKD$() = make a double float into a string
			MKS$() = make a single float into a string
			MKI$() = make an integer into a string

and are used for writing binary numeric data to a file.
The usage would be:
		LSET A$ = MKD$(double#)
		LSET B$ = MKS$(single!)
		LSET C$ = MKI$(integer) or (integer%) or (integer@)

The convert functions are:
			CVD() = convert a string into a double float
			CVS() = convert a string into a single float
			CVI() = convert a string into an integer

The usage would be:
		double# = CVD(A$)
		single! = CVS(B$)
	     integer% = CVI(C$)

Here is a new Test.bas, using these new functions to try:

'  test.bas version 48
    CLS
    az#=1.012345
    bz!=123.456
    cz%=123456
    dz = 12345
    w$ = "end"
    rec% = 1
'
    OPEN "R", #1, "test.txt", 34
    FIELD #1, 4 AS A$, 4 AS B$, 8 AS C$, 8 AS D$, 10 AS E$
    FOR x% = 1 TO 5 STEP 1
        LSET A$ = MKI$(dz)
        LSET B$ = MKI$(cz%)
        LSET C$ = MKS$(bz!)
        LSET D$ = MKD$(az#)
        RSET E$ = w$
        PUT 1, rec%
        rec% = rec% + 1
    NEXT x%
    CLOSE 1
    CLEAR
'
    OPEN "R", #1, "test.txt", 34
    FIELD #1, 4 AS A$, 4 AS B$, 8 AS C$, 8 AS D$, 10 AS E$
    GET 1, 1
'
    az# = CVD(D$)
    bz! = CVS(C$)
    cz% = CVI(B$)
    dz =  CVI(A$)
    PRINT "az#="; az#
    PRINT "bz!="; bz!
    PRINT "cz%="; cz%
    PRINT "dz ="; dz
    CLOSE 1
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

This example uses a FOR/NEXT loop to write five consecutive records to disk.

Now examine Test.txt.
Looks pretty weird, huh?
Remember, with the exception of string variable w$, all the variables were numeric values. 
And, that's what number values look like in their binary form. The reason we wrote w$ ('end') was simply for the purpose of placing a visible marker, so that we could see where the record ends. Not only do random access files allow access to individual records within the file, numbers are written to disk in a visually 'encrypted' form.

There is one more important thing to know about FIELDing numbers. That is, that regular integers, (of type: integer and integer%) must be FIELDed to a length of four (4) bytes and ALL other number types must be FIELDed to 
eight (8) bytes. 
Example:
    FIELD #1, 4 AS integer$, 4 AS integerX$,...
    FIELD #1, 8 AS float$, 8 AS double$, 8 AS longinteger$,...

where   integer = variable		(4 bytes)
and    integerX = variable%		(4 bytes)
and longinteger = variable@		(8 bytes)
and       float = variable!		(8 bytes)
and      double = variable#		(8 bytes)

Some other useful functions are:
		LOC() = returns the offset pointer within the current file
		LOF() = returns the length, in bytes, of the current file
		LEN() = returns the length of a string variable

Usages would be:
		pointer% = LOC(buffer)
		    len% = LOF(buffer)
		     len = LEN(mystring$)

Here is a Test.bas showing them in use:

'  test.bas version 49
    CLS
    '
    OPEN "R", #1, "test.txt", 34
    FIELD #1, 4 AS A$, 4 AS B$, 8 AS C$, 8 AS D$, 10 AS E$
    GET 1, 2
'
    pointer% = LOC(1)
    PRINT "file offset = "; pointer%
'
    len% = LOF(1)
    PRINT "file length = "; len%
'
    string$ = E$
    len = LEN(string$)
    PRINT "len string$ = "; len, ">"; string$; "<"
'
    az# = CVD(D$)
    bz! = CVS(C$)
    cz% = CVI(B$)
    dz =  CVI(A$)
    PRINT "az# = "; az#
    PRINT "bz! = "; bz!
    PRINT "cz% = "; cz%
    PRINT "dz = "; dz
    CLOSE 1
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

' Count to One Million - program
'
    PRINT "counting to one million..."
    PRINT
    curtime$ = TIME$
    PRINT "Start time is:", curtime$
    PRINT
    FOR ndx = 1 TO 1000000 STEP 1
    NEXT ndx
    curtime$ = TIME$
    PRINT "End time is:", curtime$
' ------------------------------------------
TheEnd:
  END
' ------------------------------------------

Summary:
This document is a only a brief description of the Bxbasic language syntax and by no means anywhere near to being complete. This document doesn't even include all of the Bxbasic commands nor string and math functions.
Future releases will add new features, resolve bugs and other undocumented features. If you have any suggestions or functions you'd like to see added (sooner than later), your feedback is very welcome. If you do find any errors or typos you'd like to report, you can contact me through the 
QDepartment at:  	http://groups.yahoo.com/groups/QDepartment/
-or-
QDept_Group at:  	http://groups.yahoo.com/groups/QDept_Group/

The Author,
Steve
-----------------------------------------------------
Blunt_Axe_Basic Project
Bxbasm/Bxbasic
Copyright:(c) sarbayo, 2001,02,03,04
Alpha Version 1.05
-----------------------------------------------------