Table of Contents
This document describes Yabasic version 2.75105, an experimental version of Yabasic 2.751 built for Windows with several additions and modifications. The Windows binary is packaged in the file yabasic-2.75105.win32.zip which also includes all the files distributed with Yabasic 2.751. Modified source files are in the file yabasic-2.75105.src.zip. While the modified source files should compile on Linux, most of the additions and modifications are not tested on Linux, and some are either not applicable, or are known to cause problems. See the file yabasic-2.75105.txt for additional notes.
The home page for Yabasic is http://www.yabasic.de/ were you will find the current version and main documentation. The home for this experimental version is http://www.mhuffman.com/resource/basic/. The numbering system for this version adds .00001 incrementally to the base Yabasic version it was derived from. For example: 2.75101, 2.75102, etc.
Yabasic is a traditional BASIC interpreter, however it is not a QBasic clone (QBasic shipped with versions of Microsoft DOS 5.0 through Windows 95). The author of Yabasic has added many useful functions and statements with some noticeable roots from the UNIX shell, C, and perhaps Perl. He has also omitted some QBasic functions and statements, implemented identical functionality with different key words, and implemented slightly different syntax in places. The additions and modifications described here are intended to add a bit more compatibility with QBasic and GW-Basic; and to add some additional functionality I personally find useful.
The vast majority of additions and modifications are merely "syntactic sugar" added to an already fine BASIC interpreter implementation. The most noticeable difference, however, is the modified interactive console, which was inspired directly by Python.
BASIC stands for Beginners All-purpose Symbolic Instruction Code . A beginning programmer is more likely to experiment with ideas and sample code fragments if the code is easy to enter and experiment with. While high-level language interpreters are a vast improvement over most compiler environments, one usually must open a text editor, possibly set up a working directory structure, usually open a command-line console, then repeat an edit-save-run cycle. This implementation of Yabasic supports an interactive console where statements can be entered and evaluated immediately without closing the console; and the interactive session command history is accessible during the session and can be saved to a disk file.
Using this version of Yabasic in interactive mode is as simple as:
C:\>yabasic
This is yabasic version 2.75105 built on Windows Sun Jul 25 21:35:53 2004
Copyright 1995-2004 by Marc-Oliver Ihm
Enter Yabasic statements; End of File (Ctrl-Z / Ctrl-D) to quit.
s$ = peek$("history", "filename") appends console buffer to filename.
See the documentation within the start-menu for more information.
: a = 3 : b = 8
: print a + b, "\t", a - b
11 -5
: do
+ input "Enter a number, 'Q' to quit: " n$
+ if (ucase$(left$(n$, 1)) = "Q") break
+ for i = a to b
+ print val(n$) * i, "\t";
+ next i
+ print
+ loop
Enter a number, 'Q' to quit: 2.33
6.99 9.32 11.65 13.98 16.31 18.64
Enter a number, 'Q' to quit: q
: h$ = peek$("history", "history.txt")
: shell("dir history.txt | find \"history.txt\"")
07/25/2004 09:46 PM 286 history.txt
: ^Z
C:\>
|
The example shows an interactive session where some single-line statements are executed, a for loop inside a do loop, then the history buffer is saved to the file history.txt. A shell command is run to verify the file, and finally the interactive session is terminated. The resulting history file is shown below.
# Yabasic history: Sun Jul 25 21:45:27 2004
a = 3 : b = 8
print a + b, "\t", a - b
do
input "Enter a number, 'Q' to quit: " n$
if (ucase$(left$(n$, 1)) = "Q") break
for i = a to b
print val(n$) * i, "\t";
next i
print
loop
h$ = peek$("history", "history.txt")
|
ucase$() — convert a string to upper case
u$ = ucase$(a$)
The ucase$() function accepts a single string argument and converts it to all upper case. Duplicates the upper$() function; added for compatibility with QBasic and GW-Basic.
repeat
line input "Enter a string, 'Quit' to exit: " input$
print "You entered: ", input$
until (ucase$(input$) = "QUIT")
This example prompts for input, and converts the input string to all upper case so that it can make a single test against the string literal "QUIT"
lcase$() — convert a string to lower case
l$ = lcase$(a$)
The lcase$() function accepts a single string argument and converts it to all lower case. Duplicates the lower$() function; added for compatibility with QBasic and GW-Basic.
input "User Name: " uname$
if (uname$ <>> lower$(uname$)) error "User names must be all lowercase."
This example prompts for a user name and checks if it is all lower case.
ucfirst$() — convert the first character of a string to uppercase
uf$ = ucfirst$(a$)
The ucfirst$() function accepts a single string argument and converts the first character to upper case.
input "Enter your first name: " fname$ input "Enter your last name: " lname$ print ucfirst$(lcase$(fname$)) + " " + ucfirst$(lcase$(lname$))
This example converts each input string to "capital case." Example input and output:
Enter your first name: boris Enter your last name: BADENOV Boris Badenov
lcfirst$() — convert the first character of a string to lowercase
lf$ = lcfirst$(a$)
The lcfirst$() function accepts a single string argument and converts the first character to lower case.
words$(0) = "zero" : words$(1) = "ONE" : words$(2) = "TwO" : words$(3) = "thREE"
for i = 0 to 3
print lcfirst$(words$(i)),
next i
This example will print:
zero oNE twO thREE
environ$() — return an environment variable
evar$ = environ$(key$)
The environ$() function requires one augment, the name of an environment variable; and returns the value of the environment variable. This function duplicates the action performed by peek$("env","NAME") and is added for compatibility with QBasic and GW-Basic.
if (environ$("OS") = "Windows_NT") then
print "Probably Windows 2000 or XP"
else
print "Probably Windows ME, 98 or 95"
endif
This example reports a best guess of the user's operating system based on the OS environment variable.
space$() — return a string of space characters
pad$ = space$(n)
The space$() function takes a numeric argument and returns a string containing that number of spaces.
item$ = "Basketball,103,Gas Grill,8,Rowing Machine,20,Lawn Mower,4"
dim part$(1)
n = token(item$, part$(), ",")
name_width = 20
field1$ = "Item Name" // record field names
field2$ = "On Hand"
pad = name_width - len(field1$) // calculate number of spaces
print field1$, space$(pad), field2$ // pad string with trailing spaces
print string$(len(field1$), "-"), space$(pad), string$(len(field2$), "-")
for i = 1 to n step 2 // count by 2's (record has 2 fields)
name$ = part$(i)
onhand = val(part$(i + 1))
pad = name_width - len(name$) // calculate number of spaces
print name$, space$(pad), str$(onhand, "%3.0f")
next
This example uses several Yabasic functions to format data records in columnar format producing the following output:
Item Name On Hand
--------- -------
Basketball 103
Gas Grill 8
Rowing Machine 20
Lawn Mower 4
string$() — return a string of a single character
c$ = string$(n, char$)
The string$() function takes 2 arguments: one numeric argument and one string argument. It returns a string equal in length to the numeric argument composed of the first character in the string argument.
title$ = "The Adventures of Rocky and Bullwinkle"
title_len = len(title$)
page_width = 80
n = int((page_width - title_len) / 2)
print space$(n), title$
print space$(n), string$(title_len, "*")
This example centers a title on a screen 80 columns wide "underlined" with a string of '*' characters the same length as the title.
join$() — return a string joined with elements of an array
a$ = join$(str$, str_array$()), a$ = join$(str$, num_array())
The join$() function takes 2 arguments: a string of zero or more characters; and either a string array reference or a number array reference. A string is returned with the string argument placed between each element of the array. In the case of multi-dimensional arrays all dimensions of the array are joined beginning with each element of the first dimension, then the next dimension, etc.
join$() is more or less the opposite of token(), but not quite. The string returned from an array joined with j$, then later tokenized (using token()) using j$, will have one more element than the original array because token() (and split()) return arrays with an empty first element. Also, while join$() can join arrays of strings or numbers, token() and split() always return a string.
dim parts(7) // 8-element array of numbers
for i = 0 to arraysize(parts(), 1)
parts(i) = 2^i // fill with powers of 2
next i
glue$ = ", "
joined_str$ = join$(glue$, parts())
print joined_str$ // "1, 2, 4, 8, 16, 32, 64, 128"
dim tokenized$(1)
n = token(joined_str$, tokenized$(), glue$) // 9-element array of strings
print arraysize(parts(), 1), n, arraysize(tokenized$(), 1) // 7 8 8
dim parts2(arraysize(tokenized$(), 1) - 1) // 1 element smaller than tokenized$()
for i = 0 to arraysize(parts2(), 1)
parts2(i) = val(tokenized$(i+1)) // convert strings back to numbers
next i
This example creates and fills an array of numbers, then joins the array with a comma and a space. To demonstrate the relationship between join$() and token() the example code creates a second array from the string returned by join$() using the same "glue" string for the token. Note that the return value from token() is the same as the return value from arraysize() for the new array, which is 1 greater than the original array of numbers. Note also that the new array is an array of strings. Finally, a third array of numbers is created (1 element smaller than the second array) and filled with the value of each string element from the second array, starting with the second element (because token() returns arrays with an empty first element).
pos(), pos(n) — return the cursor column
col = pos(), col = pos(n)
The pos() function returns the 0-based cursor column (e.g. the first column is 0) The alternate form with a single numeric argument is for compatibility with QBasic and GW-Basic; the argument is simply a dummy parameter and is ignored. Like other "advanced" screen functions, the clear screen statement must be issued before calling pos() .
clear screen
print pos(), ", ", csrlin() // 0, 0
print "pos(), csrlin(): ";
x = pos()
y = csrlin()
print x, ", ", y // pos(), csrlin(): 17, 1
print at(50, 10) pos(), ", ", csrlin() // 50, 10
This example shows the upper-left cursor coordinates as (0, 0) immediately after clear screen, the cursor on column 17, row 1 after printing the string "pos(), csrlin(): " (without printing a newline), and finally matches the coordinates pass as the arguments to at().
csrlin() — return the cursor row
row = pos()
The csrlin() function returns the 0-based cursor row (e.g. the first row is 0) Like other "advanced" screen functions, the clear screen statement must be issued before calling csrlin() .
Seepos
kill() — delete a file
n = kill(file_spec$)
The kill() function accepts one argument: a string that specifies a file, including path if desired, to be deleted. It returns 0 if the file is deleted successfully, otherwise it returns a system error code. kill() is added for compatibility with QBasic and GW- Basic (although those languages implement it as a statement, which does not return a status) and as a convenience. The alternate way to delete files in Yabasic is via the system() or system$() functions, also accept the applicable operating system wild-card characters for file name expansion.
NUM_RECORDS = 4
tempfile$ = "temp.txt"
fh = open(tempfile$, "w") // open temp file for writing
if (not fh) error "Could not open " + tempfile$
for i = 0 to NUM_RECORDS - 1
read name$ // read data records into temp file
print #fh name$
next i
close #fh // close temp file
name$ = system$("sort " + tempfile$) // sort file, capturing the output
dim sorted$(1) // new array for sorted records
dim_max = token(name$, sorted$(), "\n") // fill array of records
for i = 1 to dim_max // (5-element array, element 0 is empty)
print sorted$(i) // display sorted names
next i
if (kill(tempfile$)) then // delete the temp file
print "File deletion error: " + tempfile$
else
print "File deleted: " + tempfile$
endif
data "Do-Right,Dudley,017"
data "Badenov,Boris,010"
data "Whiplash,Snidely,004"
data "Fatal,Natasha,008"
This example uses the operating system to sort a set of data records that have first been written to a temporary file, then deletes the file. Note that system("del " + tempfile$) (Windows) or system("rem " + tempfile$) (Linux) would also work.
Yabasic does not have a built-in sort function (nor most other "traditional" BASIC implementations that I know of), therefore I could either write my own routine in Yabasic or call on the operating system. Linux and Windows (versions > Win98) have many useful and powerful sort options; and I do not have the confidence that I can improve on the sort routines written by the designers of my operating system. The Yabasic system$() that returns the system's STDOUT makes it practical to let the operating system do some of the work and get the results back into a Yabasic program.
unlink() — delete a file
n = unlink(file_spec$)
The unlink() function duplicates, and is a synonym for, the kill() function.
See kill
peek$ — retrieve various internal string-information
print peek$("foo")
The following sub-functions have been added to peek$():
Returns the full path to yabasic.exe that executed this program, or, if the Yabasic program has been bound to yabasic.exe, the full path to the bound program.
Returns the name of the source file being executed by Yabasic; if the program is bound an empty string is returned.
Returns the full path to the source file being executed by Yabasic; if the program is bound an empty string is returned.
Returns the Windows short path name for a Windows long path.
Returns the interactive buffer as a string.
Saves the interactive buffer to a file and returns the buffer as a string. The file is opened in append mode: if it already exists the current history buffer will be appended to the end; if the file does not already exist a new file will be created.
# peek.yab
# bind command line: yabasic -bind peek.exe peek.yab
name$ = peek$("name")
if (peek("isbound")) then
p$ = peek$("yabasic")
i = rinstr(p$, "\\")
name$ = mid$(p$, i+1)
endif
print "program name: ", name$
print
print "peek$(\"yabasic\"): ", peek$("yabasic")
print "peek$(\"fullname\"): ", peek$("fullname")
print "peek$(\"name\"): ", peek$("name")
longpath$ = "C:\Documents and Settings\mike\My Documents\long_name.txt"
print "longpath: ", longpath$
print "shortpath: ", peek$("shortpath", longpath$)
Executed by yabasic.exe (located in D:\Util\) the following output is produced:
D:\yabasic-2.751\doc>yabasic peek.yab
program name: peek.yab
peek$("yabasic"): D:\Util\yabasic.exe
peek$("fullname"): D:\yabasic-2.751\doc\peek.yab
peek$("name"): peek.yab
longpath: C:\Documents and Settings\mike\My Documents\long_name.txt
shortpath: C:\DOCUME~1\mike\MYDOCU~1\LONG_N~1.TXT
Executed from the same working directory as above, however bound to yabasic.exe as peek.exe, the following output is produced:
D:\yabasic-2.751\doc>.\peek
program name: peek.exe
peek$("yabasic"): D:\yabasic-2.751\doc\peek.exe
peek$("fullname"):
peek$("name"):
longpath: C:\Documents and Settings\mike\My Documents\long_name.txt
shortpath: C:\DOCUME~1\mike\MYDOCU~1\LONG_N~1.TXT
environ — set an environment variable
environ "NAME=KEY"
environ sets a system environment variable with a single string of the form "VAR_NAME=VALUE". When Yabasic executes a source file, or when Yabasic runs in interactive mode, it starts a new command shell at the beginning and exits that command shell when the program ends or when the interactive session is terminated. The new environment variable is only available to the current running shell. Any environment variables set within Yabasic will not be available when the program or interactive session terminates.
# env.yab
# set new TEMP variable with environ statement
print "environ$(\"TEMP\") before environ statement: ", environ$("TEMP")
new_temp$ = "TEMP=" + system$("CD")
environ new_temp$
print "environ$(\"TEMP\") after environ statement: ", environ$("TEMP")
print "system$(\"echo %TEMP%\"): ", system$("echo %TEMP%")
This example sets the TEMP variable to the current working directory for the current shell; upon termination of the program TEMP will have its original value. Output from the example on a Windows XP system is shown below bracketed by echo commands to show the value of TEMP before and after execution of the program; environ$() is called to show the value of TEMP within the program's shell.
D:\yabasic-2.751\doc>echo %TEMP%
C:\DOCUME~1\mike\LOCALS~1\Temp
D:\yabasic-2.751\doc>yabasic env.yab
environ$("TEMP") before environ statement: C:\DOCUME~1\mike\LOCALS~1\Temp
environ$("TEMP") after environ statement: D:\yabasic-2.751\doc
system$("echo %TEMP%"): D:\yabasic-2.751\doc
D:\yabasic-2.751\doc>echo %TEMP%
C:\DOCUME~1\mike\LOCALS~1\Temp
system — terminate the program and return to operating system
system
Terminates the program and returns to the operating system. Synonym for exit, added for compatibility with QBasic and GW-Basic to facilitate comparing code fragments between the 2 implementations.
do
print "Do you want to continue ?"
input "Please answer y(es) or n(o): " a$
if (lcase$(left$(a$, 1)) = "n") then
system
end if
loop
This example will run almost unaltered under MS QBasic (QBasic requires a coma between the input statement prompt and variable name)
shell, shell() — start a new command shell, send a command to the command shell
shell, shell(command$)
The shell statement without an argument simply launches a new command shell and remains in the shell until the user enters exit. Used with a command string argument shell is similar to system() or system$(), however as a statement it does not return a value. Added for compatibility with QBasic and GW- Basic as well as a convenience so that a "throw away" variable does not need to be assigned when a return value is not needed.
clear screen
print "Please verify that the file foo.ini is in the current directory"
print "and that the [BAR] section contains the following line:"
print
print " buffer: .\\tmp.txt"
print
do
input "[S]tart a command shell; [E]dit foo.ini; [C]ontinue: " a$
if (ucase$(left$(a$, 1)) = "S") then
shell : break
elsif (ucase$(left$(a$, 1)) = "E") then
shell("edit foo.ini") : break
elsif (ucase$(left$(a$, 1)) = "C") then
break
else
print "Enter S, E, or C"
endif
loop
shell("type foo.ini")
print "Press any key to continue...";
a$ = inkey$
This example allows a user to open a shell to perform directory/file maintenance, directly edit a file, or continue with the program.
cls — clear the screen
cls
Clears the screen with a call to system("cls") under Windows or system("clear") under Linux. Added for compatibility with QBasic and GW-Basic, brevity, and originally as a kludge to clear the screen without changing the default screen color attributes. Note that cls is not a synonym for clear screen; you must still call clear screen before using any of the advanced I/O functions and statements such as print at(), etc.
cls // clears the screen
print at(5, 5) "test" // Error: need to call 'clear screen'
poke — change selected internals of yabasic
poke "foo", "bar"
The following sub-function has been added to poke:
Sets a system environment variable; duplicates the environ statement, with the same limitations on the scope of the variable being set.
new_temp$ = "TEMP=" + system$("CD")
poke "env", new_temp$
This example sets the TEMP variable to the current working directory for the current shell
clear_screen — erases the text window
erases the text window
Under Windows 2000 or XP a user can control the console (command prompt) window foreground and background colors, either via the properties dialog, or the COLOR command. Yabasic sets a gray foreground on black background when clear screen is called regardless what attributes a user was previously using. This implementation of Yabasic preserves the user's screen attributes and uses them for clear screen and subsequent I/O on the console.
See the main Yabasic documentation
color — print with color
print color(fore$) text$
print color(fore$, back$) text$
Not a separate command, but part of the print-command; may be included just after print and can only be issued after clear screen has been executed.
color() takes one or two string-arguments, specifying the color of the text and (optionally) the background. This implementation of Yabasic expands the original 8 colors to 16 colors as supported by Windows 2000 and XP.
The one or two strings passed to color() can be one of the following:
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
color() can only be used, if clear screen has been issued at least once.
clear screen
for i = 0 to 15
fg$ = hex$(i)
for j = 0 to 15
bg$ = hex$(j)
print color(fg$, bg$) " " + fg$ + bg$ + " ";
next j
print
next i
This example prints a table of all possible color combinations using the equivalent Windows color attribute codes.