Yabasic |
Version
2.72 |
||||
|
|||||
|
This document describes the features of yabasic. In short, yabasic implements the most common (and simple) elements of the basic-language, plus some graphic facilities; anyone, who has ever written basic-programs should feel at home.
This page covers all the features of yabasic, you don't need any other text to learn it. In fact, there is no other text about yabasic, neither a unix-man-page nor a Windows-helpfile.
This text doesn't teach basic from scratch, it rather assumes some experience with the basic-programming-language.
There are three way to start yabasic:
1. |
You may write your basic-program
to a file (e.g. foo.yab) and call yabasic with this file as an argument: |
2. |
You may start you yabasic without
any filename. Typing |
3. |
You may put your program into
a file and insert this text as the very
first line: |
The colors, text-font and the window position should be set on the command-line , or specified in the users resource file (this is usually the file .Xresources in your home-directory); e.g.:
yabasic*background: gold yabasic*geometry: +10+10 yabasic*font: 9x15
This sets the foreground of the graphics-window to blue, the background to gold, the window will appear at position 10,10 and the text-font will be 9x15.
After you have run the setup program, yabasic can be invoked in three ways:
1. |
Choose "yabasic" from the start-menu: Yabasic will come up with a console window and wait for a program to be typed in right away. |
2. |
Click with the right mousebutton on your desktop. Choose "new" from the context-menu that appears; this will create a new icon on your desktop. The context-menu of this icon has three entries "Execute", "Edit" and "View docu" (which shows the embedded documentation, if any); a double-click executes the program. |
3. |
Create a file containing your yabasic-program. This file should have the extension ".yab". Double-click on this file then invokes yabasic, to execute your program. |
To choose the default-values for graphic-font, fontsize and window position, you have to edit the registry.
Yabasic stores its defaults under:
You may edit the subkeys "font" and "geometry"; these subkeys accept the same values as the corresponding command line options -font and -geometry. Command line options take precedence over registry defaults.
This is the first example:
input "Enter two numbers:" a,b print a,"+",b,"=",a+b print "Please enter your Name:"; INPUT a$ print "Hello ",a$," !"
This program produces the following output (user input is displayed like this):
2+3=5 Please enter your Name: Bill Hello Bill !
This simple program contains three different commands:
Furthermore some general properties of yabasic should be noted:
Yabasic has five arithmetic operators: + (addition), - (subtraction), * (multiplication), / (division) and ^ (power); they all behave as expected, i.e. this line of code
produces this line of output:
Note that the power operator (^) handles fractional powers: 8^(1/3) gives 2 as a result.
This section demonstrates and explains the arithmetic functions of yabasic.
To make decisions you have to use the if-statement:
input "Please enter a number" a if (a>10) then print "Your number is bigger than 10" elsif (a>5) then print "Your number is bigger than 5 but less or equal 10" else print "Your number is less or equal 5" endif
As you can see, the condition has to be enclosed in parentheses (...). The else and the elsif-part of the if-statement are optional and can be omitted, as in this example:
input "Please enter a number" a if (a>10 and a<20) then print "bigger than 10":print "but less than 20" fi
Note that endif can be written as fi too.
Just in case you want to write even less, you may try:
input "Please enter a number" a if (a>10 and a<20) print "bigger than 10 ":print "but less than 20"
Note, that then and endif (or fi) have been omitted; As you might expect, both print-statements are executed or not, depending on the condition. Note however, that previous versions of yabasic behaved differently (and quite counterintuitive) in this respect.
Next, have a look at the condition (a>10 and a<20) of the if-statement:
For Convenience you may store the result of a comparison within a variable and retrieve it later:
input "Please enter a number between 1 and 10: " a okay=(a>=1 and a<=10) if (not okay) print "autsch !"
The result of the comparison is stored within the variable okay which is simply queried within the if-statement.
The above example can be rewritten, showing the special constants TRUE and FALSE:
input "Please enter a number between 1 and 10: " a if (a>=1 and a<=10) then okay=TRUE : else okay=FALSE : fi if (not okay) print "autsch !"
input "Please enter your choice" a$
switch a$: case "q":end case "?":case "h": print "Sorry, no help available" :break case "p": print "Howdy !" end switch
This program checks its input (in the variable a$) against many different values, reacting accordingly. Of course you may do this with an if-statement, but it would be much harder to understand.
Note finally, that you may just as well switch on arithmetic expressions.
Basic has always been simple and strong in string-processing; and yabasic also tries to continue in this tradition:
for a=len(a$) to 1 step -1:print mid$(a$,a,1);:next a print " is ",a$," reversed !"
If you try this program, you will get this output:
olleh is hello reversed !
input "Please enter a word" a$
a=len(a$):repeat print mid$(a$,a,1);:a=a-1 until(a=0) print " is ",a$," reversed !"
input "Please enter a word" a$ a=len(a$):while(a>0) print mid$(a$,a,1);:a=a-1 wend print " is ",a$," reversed !"
input "Please enter a word" a$ a=len(a$):do: print mid$(a$,a,1);:a=a-1:if (a=0) then break fi: loop print " is ",a$," reversed !"
do
a$=inkey$ if (a$="q") break if (a$=" ") continue print a$ loop
The above example reads characters from the keyboard and prints them to screen; however: If you enter "q" the loop is terminated (by the break-statement) and if you enter " " (space) the loop starts all over without printing (caused by the continue-statement)
Within the for-next-loop above the string-functions len() and mid$() are applied, but there are many more string functions:
Escape-sequence |
Resulting Char |
\n |
newline |
\t |
tabulator |
\v |
vertical tabulator |
\b |
backspace |
\r |
carriage return |
\f |
formfeed |
\a |
alert |
\\ |
backslash |
\` |
single quote |
\" |
double quote |
Here is another example which introduces the rest of yabasic's string-functions:
label again print "Please enter a string containing the word \"yabasic\"" input a$ if (instr(lower$(a$),"yabasic")<>0) then gosub thanx else print "No, please try again !" endif goto loop label thanx print "Thanks a lot !" return
If you run this program you will receive the following output:
?thequickbrownfox No, please try again ! Please enter a string containing the word "yabasic" ?jumpedyabasicoverthelazydog Thanx.
l$=" one two three " dim words$(1) num=token(l$,words$()) for a=1 to num:print words$(a):next a
l$="::one::two:three::four" dim words$(1) num=split(l$,words$(),":") for a=1 to num:print "Token: ",words$(a):next a
will produce this output:
glob-condition |
True/False ? |
---|---|
glob("abcd","abc?") |
true |
glob("abab","*") |
true |
glob("abc","ab??") |
false |
glob("abcdabab","ab*ab") |
true |
glob("abcd","*a") |
false |
One day you won't be satisfied with yabasic's builtin functions and commands; this will be the time to define and use your first subroutine:
print multiply$("Hello",3)
sub multiply$(a$,a)
local b$,b
for b=1 to a:b$=b$+a$:next b
return b$
end sub
This program simply prints the string HelloHelloHello which is (sort of) Hello multiplied with three. As there is no function in yabasic to "multiply" strings, the program defines it's own function multiply$() (starting with sub multiply$(a$,a)). multiply$() is a user defined string-function; you can tell from the $-sign in multiply$(), that it returns a string. multiply$() takes two arguments, a string and a number, which are passed to the function through the variables a$ and a. These variables, as well as b$ and b (defined in local b$,b), are local to the function: They are initialized as the subroutine is entered and keep their value just as long as the subroutine is executed. The computation within the subroutine is straightforward and the result is returned with the statement return b$.
Instead of return b$ you might just write return or omit the return-statement altogether; in this case an empty string (or 0.0 for numerical functions) would be returned; of course, this wouldn't be very useful for this subroutine.
Here are some examples showing, that yabasic is quite tolerant with user defined subroutines:
print sum(1,4),sum(2),sum()
sum(2,3)
sub sum(a,b)
if (numparams<2) b=1
return a+b
end sub
sub() is a numerical subroutine (because sub() doesn't contain a $-sign) and returns just the sum of its two numerical arguments. Running this program prints the line "5 3 1" which are the three values returned by the three calls to sum().
As you see the function sum() can be called with less than two arguments; in this case 0.0 is inserted for a missing numerical argument and the empty string "" for a missing string argument. However you may query local variable numparams, which is automatically created by yabasic, to get the nuber of parameters actially supplied during the subroutine call. If you omit an array argument, yabasic will supply a local dummy array instead; however, as soon as you try to access this array argument you will receive an error. Therefore it is good practice to check numparams before accessing array parameters.
Furthermore you may call a subroutine (in the example: sub(2,3)) without caring for the value returned (techincally spoken there is no distinction between functions and procedures in yabasic).
Local variables are invisible outside your subroutine, but they are newly created each time you call your subroutine; but sometimes you may want to keep the values of variables within your routines. In this case you may use static variables like this:
for a=1 to 4:stars():next a sub stars() static a$ local b$ a$=a$+"*" b$=b$+"*" print a$," ",b$ end sub
Running this program produces the following pattern:
* * ** * *** * **** *
As you see the static variable a$ keeps its value over calls to stars(), while b$ is initialized every time.
Finally note, that subroutines may easily use arrays in subroutines as parameters, local or static variables; look here for an example.
Sometimes a program might want to create a subroutine during its execution: Let's say a user wants to enter an arbitrary function, which the program should then plot on the screen:
input "Please enter an arithmetic expression: f(x) = " f$
compile "sub f(x):return "+f$+":end sub" for x=1 to 10:for i=1 to f(x):print "*";:next i:print:next x
This program reads an arithmetic expression into the variable f$; possible values would be "sin(x)" or "x*x". With this arithmetic expression a simple function definition is created and handed over to the compile-command, which turns its string argument into valid yabasic-code. After this you can simply use the newly defined function f(x), as in the third line, which does a simple plot of the function.
A different feature (but still related with subroutines) is the ability to execute a function by specifying its name and arguments: execute("f",x) is exactly the same as f(x); of course execute("f",x) is ugly, but it might be used to plot a function which is specified by its name only:
sub plot(f$)
local x,y,a
for x=1 to 10
y=execute(f$,x)
for i=1 to y:print "*";:next i print
next x
end sub
With this handy plot function you may just say plot("f") to get a plot of function f. However, note that plot("x*x") would give you an error, because it would try to execute a function named "x*x" which does not exist.
Whether you want to save the value returned by execute (or whether the executed function returns one), you may use execute within an assignment or standalone: execute("f",x) and y=execute("f",x) are both valid.
Finally, you may use execute$ for functions returning a string.
A library is a separate file which contains "readymade" subroutines. Libraries are useful, if you have written a set of subroutines, which you want to use in more than one yabasic program. Better even, if someone else has written a library, which you could use without efford.
Let's go ahead and try an example (as libraries contain mostly subroutines, you may branch off and read about them first). This simply uses a library:
import ufirst print uf$("foO")
If you run this program, it prints "Foo" which is "foO" with the first character ("f") capitalized and the rest ("oO") changed to lowercase. The name of this subroutine ("uf") is just an abbreviation of "upper-first".
The Subroutine uf$() is defined in the library ufirst which is made available with the statement import ufirst. The library ucfirst is quite simple:
rem Here comes the embedded documentation: docu docu This library ufirst provides just a single function: uf$(), doc which returns its string argument all lower case except for doc the first letter, which is capitalized. doc docu e.g. uf$("foo") returns "Foo" and uf$("bAr") returns "Bar" docu a=2: rem This statement has no use ! export sub uf$(a$) : rem export uf$() return upper$(left$(a$,1))+lower$(butfirst$(a$)) end sub sub butfirst$(a$) : rem butfirst$() is only visible locally return right$(a$,len(a$)-1) end sub
If you import this library (with import ufirst) into your yabasic program, yabasic reads in the library and inserts it into your program: Any statements in the library (e.g. a=2 in the example) is executed and any subroutine (uf$() and butfirst$()) is defined. After import the variable a and the functions uf$() and butfirst$() are defined within your program. To avoid conflicts between the variables and subroutines defined in you program and those defined in the library, all variables and subroutines are prefixed with the name of the library. I.e. a is imported as ufirst.a, uf$() , is imported as ufirst.uf$() and butfirst$() is imported as ufirst.butfirst$(). You may check, that a from the library ufirst does not conflict with any a in your program with this simple program:
import ufirst a=1 print a,ufirst.a
This simply prints "1 2", prooving that "a" in your program and "a" in the library ufirst don't collide.
On the other hand you may want to use some selected subroutines from the library without prefixing them with the library name. This can be achieved by adding the keyword export to the definition of the routine (in the example: export sub uf$(a$)). Such an exported subroutine can be used without prefixing it with the library name (as in print uf$("foO")).
The library starts with a bunch of
docu (or doc) statements, which contain the embedded documentation of
the library. This embedded documentation can be viewed by calling yabasic with
the "-lib" option; you would use yabasic -lib ufirst to
view the text from the docu statements. Therefore it is always a brilliant idea to add some documentation to your library, telling what
subroutines the library provides. Furthermore you might put a small, embedded
sample program into your library, demonstrating its usage. If you enclose this
sample program with if (peek$("library"="main"))
then ... endif , your embedded sample program
is only executed, if the library is run as a program and not, if other programs
import
your library.
Once you have written some embedded documentation, you may
access it also from within your program. Just query the array docu$(), which automatically contains the text of all docu-statements.
Once you have written or received a library, you should install it. This is simple: The file containing the library should end on ".yab" (e.g. ucfirst.yab); this file should than be moved to a special directory. This special directory (e.g. c:\yabasic\lib under Windows or \usr\lib\yabasic under Unix) appears (along with the explanation of the -lib option) if you call yabasic with the option -help (i.e. yabasic -help). Once you have moved the file to the right directory, you're done ! From now on you can use the library in your yabasic programs, e.g. by writing import ucfirst. Furthermore, yabasic finds a library even if it resides in the current directory, i.e. the directory where the yabasic program (with the import-statement) lives; this is quite handy for developing and testing a library.
You may notice, that the name of the file and the name of the library (which appears in the import-statement) are always (and by construction) the same.
Having read all this stuff about libraries, you may wonder where to get libraries. One solution would be to write your own; but it would be much more preferable (because it is less work) to get and use libraries other people have written. Libraries are a new feature in yabasic, so there is no set of standard libraries yet, but I hope that users will develop and contribute useful libraries ! Go ahead !!
Yabasic provides some simple, general purpose graphic-commands:
line 0,0 to 400,400 circle 200,200,150 clear fill circle 200,200,130 clear line 0,400 to 400,0 dot 200,200 a$=inkey$ clear window text 100,200,"Hello !" print "Press any key to close the window" inkey$ close window
open printer circle 100,100,80 close printer close window
open #1,printer print #1 "Hello World !" close #1
The following program shows some further commands for drawing:
window origin "lb" new curve for x=-3 to 3 step 0.1: rem this loop draws a sine()-function y=sin(x) line to 300+90*x,200+150*y next x rectangle 10,10 to 110,60: rem draw the legend text 55,35,"sine-function","cc" inkey$ close window
This program just draws a simple sine function.
Yabasic allows to retrieve and change rectangualr regions of the screen with simple commands:
for a=0 to 200 step 10 line a,0 to a,200:line 0,a to 200,a: rem draw some pattern on the screen next a rem this is a picture of a star star$="24,24:00c10000e10000f10000f10008f3" star$=star$+"0008f30008f700fff700ffff30fff" star$=star$+"fffefffffefffff0ffff70eff700e" star$=star$+"ff000cff100eff300fff70cfff70e" star$=star$+"f7ef1ef1cf3e700e3e100c3000000" for a=50 to 150 saved$=getbit$(a,150,a+24,150+24): rem save old content of window bitblit star$ to a,150,"or": rem put star at new location pause 0.1 bitblit saved$ to a,150: rem restore old window content next a
This program moves a tiny star across the window. Yabasic
stores bitmaps within ordinary strings, e.g. the star-bitmap is contained within
the variable star$.
The getbit$()-function returns such a bitmap-string, if called with the coordinates
of a rectangle; in the example the line saved$=getbit$(a,150,a+24,150+24) stores the contents of a 24x24 rectangle with corners (a,150)
and (a+24,150+24) within the variable saved$.
Once you've got a bitmap-string you can put it on the window with the putbit-command. E.g.
putbit star$ to a,150,"or" puts the bitmap contained within star$ onto the screen at position
(a,150). The fourth, optional argument ("or" in the example) specifies,
how to combine the pixels from the window with those from the bitmap:
Mode |
Action |
---|---|
"and" |
The pixel is set, if both window pixel and the bitmap pixel are set. |
"or" |
The pixel is set, if either the window pixel or the bitmap pixel are set |
"replace" |
The pixel is set, if the bitmap pixel is set. This is the default |
"xor" |
The pixel is set, if exactly one of window and pitmap pixel is set |
"nand" |
The pixel is set, if not both window pixel and bitmap pixel are set |
"clear" |
If the bitmap pixel is set, the corrosponding window pixel is cleared |
"1" |
The window pixel is set, without regarding the bitmap |
"0" |
The window pixel is cleared, without regarding the bitmap |
If you omit the mode argument, the default "replace"
applies.
Having said all this, there is a serious drawback: You can put bitmaps on the
window, but you can't print them !
Now and then the need arises to supply a program with initial data. The next sample-program converts numbers to strings:
read maxnum dim names$(maxnum) for a=1 to maxnum:read names$(a):next a label loop input "Please enter a number: " number:number=int(number) if (number>=1 and number<=maxnum) then print number,"=",names$(number) goto loop endif print "Sorry, can't convert ",number label names data 9,"one","two","three","four","five","six" data "seven","eight","nine"
If you run this program, it goes like this:
2=two Please enter a number: 3 3=three Please enter a number: 8 8=eight Please enter a number: 12 Sorry, can't convert 12
It should be mentioned, that the functionality of the above sample-program can be achieved by using totally different language-constructs:
input "Please enter a number: " number:number=int(number) on number+1 gosub sorry,one,two,three,four,five,sorry goto loop label sorry:print "Sorry, can't convert ",number:end label one:print "1=one":return label two:print "2=two":return label three:print "3=three":return label four:print "4=four":return label five:print "5=five":return
This program produces the same output as the example above.
Have a look at this program
dim a$(3,4) for a=1 to 3:for b=1 to 4 a$(a,b)=str$(a)+","+str$(b) next b:next a print_array(a$()) dim a$(5,6) print_array(a$()) sub print_array(b$()) local x,y,a,b x=arraysize(b$(),1) y=arraysize(b$(),2) for a=1 to x for b=1 to y b$(a,b)="("+b$(a,b)+")" print left$(b$(a,b)+" ",10); next b print next a print end sub
If you run this program you will see something like this:
(1,1) (1,2) (1,3) (1,4) (2,1) (2,2) (2,3) (2,4) (3,1) (3,2) (3,3) (3,4) ((1,1)) ((1,2)) ((1,3)) ((1,4)) () () ((2,1)) ((2,2)) ((2,3)) ((2,4)) () () ((3,1)) ((3,2)) ((3,3)) ((3,4)) () () () () () () () () () () () () () ()
First this program creates the string array a$(4,3) and assigns to each element a string, which consists of the indices of the individual elements. Then the program calls the subroutine print_array() which just prints the array.
print_array() accepts an array as a parameter; when the sub is called (e.g. print_array(a$()) ), the array is passed without any indices (i.e. just a$() ).
First thing the subroutine does, is to get the size of the passed array: arraysize(b$(),1) returns the size of the first dimension of the array b$(). Likewise arraydim(b$()) returns the dimension of the supplied array (e.g. 2 in the example).
The routine print_array() not just prints the array, but also modifies it: the statement b$(a,b)="("+b$(a,b)+")" puts braces around each element. As the print_array() is called twice, array elements are modified twice, i.e. they get enclosed in double braces. This shows that the array a$() which is passed to the subroutine is modified directly. Although the subroutine uses a different name ( b$() ) for the array, it has no local copy of the array but rather works with the array from the main program ( a$() ). This behaviour is known as "call by reference" unlike the treatment of non array parameters (simple strings and numbers) which are "called by value".
After calling the routine print_array() for the first time, the sample program does another dim for the array a$(), which simply changes the arrays size. This re-dimensioning (you could just as well write redim) keeps all the old contents and initializes any new elements with the empty string (or with 0.0 for numerical arrays). If you try to reduce the size of an array (e.g. do a dim a(10) first and then dim a(5) ), the statement is ignored.
To understand the examples in this section, let us assume that a file named test.dat exists in the current directory and that it contains the following three lines:
one two three four five six seven eight nine
The next example opens that file and prints out its content:
open 1,"test.dat","r" while(!eof(1)) input #1 a$ line input b$ print "a$=\"",a$,"\", b$=\"",b$,"\"" wend
Filemode |
Result |
"r" |
Open file for reading, start reading at the beginning of the file. This is the default |
"w" |
Open file for writing, overwrite old contents |
"a" |
Append to an existing file for writing or open a new one if no file with the specified name exists |
a=open("foo") input #a a$
Back to our sample program. If your run it, you will get the following output:
- a$="one",b$="two three"
a$="four", b$="five" a$="six", b$="seven eight nine"
open #1,"test.dat","w":print #1 "abcdefghijkl";:close #1 open #1,"test.dat","r" print chr$(peek(#1))," "; seek #1,2:print chr$(peek(#1))," "; seek #1,3,"here":print chr$(peek(#1))," "; seek #1,-2,"end":print chr$(peek(#1))," "; print tell(#1) close #1
a=open("test.dat","r") while(!eof(a)) input #(a) a$ print a$ wend
- open() is used as a function, which returns the first available file number (probably 1). With the print statement you may use this file number; note however, that yabasic demands braces after the hash (as in input #(a) a$ ).
Although yabasic is by no means designed as a scripting-language, it can interact with the Operating System in a limited way:
command$="ls" else command$="dir /w" endif cont$=system$(command$) print "This is the contents of the current directory:" print cont$ print len(cont$)," characters have been printed."
The system$()-function is the heart of this program: It hands its argument over for execution to the shell of the underlying operating system; under Unix it is the bourne-shell sh and under Windows it is command.com, which will execute the argument of the system()-function.
If I run this program under Windows95, I receive the following output:
Datentraeger in Laufwerk C: heisst WIN95 Seriennummer des Datenträgers: 0B1D-10F8 Verzeichnis von C:\WINDOWS\Desktop FLOPPY.LNK EMACS.LNK DRUCKER.LNK T.YAB TELNET.LNK TEST.YAB MICROS~1.LNK CD.LNK PLATTE.LNK WATCOM~1.LNK [YABDOK~1] TEST.DAT WINDOW~1.LNK [KINO] 12 Datei(en) 2.693 Bytes 4 Verzeichnis(se) 199.753.728 Bytes frei 456 characters have been printed.
Of course, you may get something different on your system (especially if you don't have a german windows installation).
As this yabasic-program runs under Unix, as well as under Windows, the argument of the system$()-function (command$) has to be chosen according to the operating system. To find type of operating system ("unix" or "windows"), the program employs the command peek$("os").
Finally, there is a very similar command named system() (without a trailing $), which doesn't catch the output of the executed command, which instead goes directly to your terminal. system() returns a numerical value, which is generated by the executed command. If you don't care about this value, you can safely ignore it; e.g. system("dir") (without assignment) is just as valid as a=system("dir").
To print the current date and time you may write:
This gave me the following output (your output will be different of course, because the times they are changing):
The date$-string has six fields: 5 is the day of the week (0-6, 0 is sunday, 6 saturday), 08 is the month (01-12), 28 is the day of the month (01-31), 1998 is the year, Fri is the name of the day and Aug is the name of the month.
The time$-string has four fields: 13 is the hour (00-23), 51 is the minute (00-59), 53 is the second (00-59) and 0 is the time, that has elapsed since the program started.
As most fields of date$ and time$ (except the last field within time$) are fixed length, it is easy to extract fields with the mid$-function.
peek and poke are an interface to some of yabasics internals and allow to query and change yabasics states and behaviour. Unlike early homecomputers, you can't peek and poke around anywhere in memory; just a few predefined variants are allowed. An example would be:
poke "infolevel","debug"
Which would print the current infolevel and change it to "debug".
From this example you see: peek and poke accept string arguments (some poke-commands except an integer argument too) and peek may return a string (in this case it appears as peek$).
Anyway there are few peek's and poke's right now, so they may be fully enumerated:
Yabasic offers limited support for processing binary files:
These peek's and poke's for binary files should not be mixed with normal file I/O through print and input (you might get trouble with yabasic's internal buffering).
Additionally it is wise to open such files with a filemode containing "b"
For interactive programs you might want to print output at specific locations. Try the next example:
print at(10,5) "1 -- Setup" print at(10,7) "2 -- Save" print reverse at(10,9) "3 -- Quit" input at(5,12) "Your choice: " a$
If you run this program, you will get a screen resembling the following layout (note that the third line will be displayed in reverse video):
2 -- Save 3 -- Quit This line is displayed in reverse ! Your choice:
Note, that you should call clear screen before doing reverse printing. Afterwards, you may also use the at()-clause in print or input-statements to move to any location (specified by the two arguments of the at()-clause) on your screen. Note that at() can be written as @() too.
If you want colour you may try this program:
rem Prepare everything clear screen dim c$(8) for a=1 to 8:read c$(a):next a rem Print in various colors for a=1 to 8:for b=1 to 8 print colour(c$(a),c$(b)) " -- Hello -- "; next b:next a rem Move a rectangle over the screen a$=getscreen$(1,1,10,10) for a=1 to 100:putscreen a$ to a,a:next a rem Available colors data "black","white","red","blue","green","yellow","magenta","cyan"
This program prints "-- Hello --" with the eight colours known to yabasic: black, white, red, blue, green, yellow, magenta and cyan. With the statement colour(f$,b$) (or color(f$,b$)) you can choose the fore- and background colors for the following print-statement.
The second part of the sample program moves a 10x10 rectangle of characters over the screen: The getscreen$(xfrom,yfrom,xto,yto) function, converts the contents of the specified screen rectangle to a string, which can be stored away in a string variable (a$ in the example). Once you have retrieved such a screen rectangle, you may put it back to the screen at any location with the putscreen command.
Since not all terminals have the same size (of course 80x25 is the most common size), you might want to know what are the actual dimensions of your screen; There are two predefined variables for this purpose: The width of your screen can be retrieved though special peek's: peek("screenwidth") returns the width of the screen (in characters), whereas peek("screenheight") returns the height. Both peeks have meaningful values only after the first call to clear screen.
To control the way numbers are printed, use the print using statement: print 12.34 using "###.####" produces 12.3400. The format string ("###.####") consists of hashes (#) with one optional dot and it pictures the appearance of the number to print. Some examples:
Command |
Output |
Remarks |
---|---|---|
print "=",12.34 using "###.####","=" |
= 12.3400= |
The output is filled up with spaces (from the left) and zeros (from the right) as the format requires. |
print "=",12.36 using ##.#,"=" |
=12.4= |
Last digit of output is rounded. |
print "=",12.34 using #.#,"=" |
=***= |
The number can not be formatted as required. |
This way of formatting is straightforward and simple, but not very flexible; e.g. it is not possible to print numbers left-aligned or with leading zeroes. To get such effects, the print using statement allows for format strings as used by the printf()-function of the C-language. Some examples:
Print-statement |
Output produced |
---|---|
print "==",str$(12.123455,"%08.3f"),"==" |
==0012.123== |
print "==",str$(12.123455,"%8.2f"),"==" |
== 12.12== |
print "==",str$(12.123455,"%-6.2f"),"==" |
==12.12 == |
More about these formats can be found in any book on the C-language.
All these formats can be used for the str$()-function too.
Some properties of yabasic are still left to explain; here is a sample program, that employs them:
pause 1 goto 10
This program beeps once every second:
Finally, the program employs a line number (10) to mark a specific line; this feature makes yabasic more compatible with traditional basics. Line numbers are just special types of labels; they have the following properties:
A feature you might need is the ability to suppress keyboard-interrupts (i.e. pressing of Ctrl-C); normally yabasic terminates immediately, if the user presses Ctrl-C. This can be suppressed like this:
After processing of this statement keyboard interrupts are completely ignored. The default behaviour is restored with the command on interrupt break.
+ - * / ^ ? @ : # , ;
A: abs() acos() and and() arraydim() arraysize() asc() asin() at() atan()
B: beep bell bin$() break [keyboard interrupts] break [loop control]
C: case chr$() circle clear circle clear rect clear screen clear window close close printer close window colour color compile continue cos() curve
D: date$ data dec() dim do doc docu docu$() dot
E: else elsif end endif end sub eof() eor() error euler execute() execute$() exit exp() export
F: false fi fill for frac()
G: getbit$() getscreen$() glob() gosub goto
H: hex$()
I: if import inkey$ input input at input # instr() int() interrupt
J:
K:
L: label left$() len() line line input line to local log() loop lower$() ltrim$()
M: map() mapx() mapy() max() mid$() min() mod() mouseb mousemod mousex mousey
N: new curve next not numparams
O: on gosub on goto open open printer open window or or() origin
P: pause peek peek$ pi poke print print at print using print # printer putbit putscreen
Q:
R: ran() rectangle read rem redim repeat restore return reverse right$() rinstr() rtrim$()
S: seek() sig() sin() static step split() sqr() sqrt() str$() sub switch system() system$()
T: tan() tell text then time$ to token() trim$() true
U: until upper$() using
V: val()
W: wait wend while window window origin
X: xor()
Y:
Z:
Arrays
Binary files
Bitmanipulation
Case of Keywords and Variables
Command line arguments
Conditions in the if-statement
Escape Sequences within strings
Formatting numbers
Getting mouse input
Globbing
How the input-statement chops a line into pieces
Keyboard interrupts
Line numbers
Multiple commands in one line
Printing Text
Random access to files
Specifying Windows-pathnames
Variables
Yabasic started sometime around eastern 1995; a first version was completed about one month later, still missing many features. After this quick start a long period of adding features and squashing bugs followed, which has more or less persisted until today.
The only interruption during those peaceful days came in the summer of 1996, when I got my Windows95-machine: Porting yabasic took two weeks and writing an installation program took me a month.
You may have noticed from the previous section, that yabasic made quite a rapid start; this is mainly due to flex and bison, the prime tools, used to implement yabasic.
Bison and flex take the grammar and produce a C-program, which implements this grammar. The only thing left to the programmer is to put flesh on this skeleton.
This process is remarkably efficient: 17 KBytes of flex and bison instructions generate 129 KBytes of C-code, which has to be compared with the 108 KBytes of C-code which I wrote. Together these implement the functionality of yabasic. So actually most of the code has been generated by flex and bison !
Although yabasic behaves mostly like an interpreter, in fact it is not. Rather it's a compiler: If you give it any basic-code for execution, the code is compiled, yielding instructions for a simple stack-machine; these instructions are then interpreted immediately, so that you will never get in touch with the stack-machine. You can find out the time needed for this process if you invoke yabasic with infolevel set to note.
Yabasic may be copied only under the terms of either the Artistic License or the GNU General Public License (GPL).
Earlier versions of yabasic have been subject to the GPL alone and it is kept for backward compatibility. Since version 2.60 you have the choice to use yabasic under the terms of the Artistic License, which gives you the right to use and distribute yabasic in a more-or-less customary fashion, plus the right to make reasonable modifications, while giving the original author some semblance of artistic control over the development of yabasic.
Regardless which license you choose (GPL or Artistic) for yabasic, it does not apply to your own yabasic-programs. The programs you write are your own work and you may use any license you like.
Finally some examples of what is possible under the terms of the Artistic License:
If you are still in doubt, please check out the licenses above.