BCL -- a small floating point calculator/compiler for the portfolio by: Peter Baltus Estherdal 14 5551 BL Valkenswaard the Netherlands email: pbaltus@neabbs phone: 04902-47194 Release 1.3á October 27 1991 Contents: 1. Introduction 2. Using BCL 3. Customizing BCL 4. BCL Machine Limits 5. Future plans & improvements 6. Copyright, source code, etc. 7. Acknowledgements 8. Update history 1. Introduction This is the second public release of BCL, a small calculator/compiler for IBM compatibles, optimized for use on an Atari Portfolio computer. You can use BCL to: - carry out scientific calculations in RPN syntax - write forth-like programs for numerical calculations - create pixel & line graphics - experiment with threaded languages - plot functions - find zeroes of functions This version of BCL does not support strings or fancy screen operations, and is therefore not the ideal tool to write general text based applications (although there are primitives to read the keyboard and write to the screen). BCL is small, and programs written in BCL can be even smaller. It is ideal for interactive prototyping and calculations. The program was created for personal use and is based on old ideas, old code, and experiments with threaded languages. What I really wanted was a replacement for the built-in calculator of the Portfolio that would support scientific functions, and also would be programmable in a forth-like programming language. The forth implementations I had access to did either not support floating point (e.g. '79 FIG forth) or were by far too big (e.g. Polymath). Therefore I decided to write a program myself, and added a few additional features while doing so: - robustness: most forth like languages are so flexible that they make it extremely easy to mess up your memory, and on a Portfolio therefore also your C: disk. Even though I am not sure that it is impossible to do such things using BCL, I am convinced that it is much more difficult to mess things up. - images: the compiled programs (binary images) can be saved independent from the actual BCL machine (BCL.EXE). This saves a lot of disk space compared to most other programming languages. - size: Only a minimum set of primitive words have been implemented in the BCL machine, but these words implement high level functions. This makes BCL easy to learn and compact at the same time. - customization: It is possible to build images from scratch, giving functions whatever names you prefer, and leaving out any functions you don't need. In fact, the only word available in BCL when started cold is the word "primitive", needed to create references to primitives in the BCL machine. - graphics: The portfolio has a nice graphics screen (256x64 pixels) but the built in applications don't use this. BCL allows access to the screen for pixel and line drawing - memory use: BCL only claims the memory which it actually needs. This means that you will be able to start the portfolio applications by pressing the appropriate keys (e.g. /|\ e for editor) from within BCL. When you exit an application you started this way, you will return to the point in BCL where the application was invoked. This only works when sufficient working memory is available: when the c-disk is enlarged to over 64k (using fdisk 64 or larger) you might find that built-in applications result in a "not enough memory" error message, especially when they load some large file. 2. Using BCL BCL is distributed as an archive containing several files. When you unpack the archive, you should find the following files: files.txt a file listing all files in the archive bcl.exe the BCL machine, or actual program b.bat batch file which starts BCL with a standard image std.bcl the standard image for BCL plot.bcl an enhanced image with function plotting and zero finding macros bcl.src this file contains all definitions for the std.bcl image and is only needed when you want to customize bcl plot.src this file contains the additional definitions for plot.bcl and is needed when you want to modify these functions bcl.doc this file bcl.adr definition of all words in bcl in portfolio address book format plot.adr definition of all words in plot in portfolio address book format bcl13.new release notes for the current BCL release bcl.pas the source file from which bcl can be compiled. The current executable (bcl.exe) has been compressed after execution using lzexe 0.91 from Fabrice Bellard. You only need bcl.exe and std.bcl in order to run bcl. In fact, bcl.exe will run all by itself, but it won't do anything useful. Make sure that bcl.exe is in a directory which is in your path (if you don't know what this is, just put it in whatever directory you are currently in), and put std.bcl in your current directory. To start the BCL program for normal operation, type "BCL STD" at the command prompt. This will start bcl with the standard image (std.bcl). You screen will clear and a horizontal line will be drawn across the lower part of the screen. Now BCL is ready to accept your input. Input consists of words that you type on the keyboard. Words are separated by spaces (hit the space bar) or by returns (hit the enter key). The words which have been defined in BCL can be found by typing the word "list" followed by a space or return. You will see many familiar words like "+", "sin", "repeat", "constant" and some others which might be less familiar, like "allot" and "jz". A list of these words follows at the end of this chapter, and is also included in file "bcl.adr" in Atari Portfolio address book format. Let's try a simple calculation: add 1 and 2 together and find that this makes 3. For this example, I will use the word to indicate that you should hit the space bar, and to indicate that you should hit the enter key. Other text should be typed as is. Now type: 1 You will see that the number 1 has been put on the stack (just above the line on the display). Now type: 2 You will see that the number 1 has moved up to the 2nd position on the stack and that the number 2 has been put on the head of the stack (just above the line). Now type: + You will see that the numbers 1 and 2 have been removed and that a number 3 has appeared on the head of the stack. What has happened is that the word + has been carried out. The action of this word is to take the first two numbers from the stack, add them, and put the result back on the stack, just as on an HP calculator. Similarly, you can use "-", "*", "/" and "^" for subtraction, multiplication, division, and powers respectively. Other words only operate on a single number, which includes most mathematical functions. Try the following: pi 2 / sin This carries out the calculation sin(pi/2), resulting in the number 1 (or at least 0.99999999999, which for most practical purposes is close enough). Other functions can be found in the list at the end of this chapter. It is also possible to store numbers for future use. Two kinds of numbers are distinguished: constants and variables. If you define a number with the intention that it never will have to change, you use a constant. In fact, the word pi used above is an example of a constant. The chances of pi ever changing value are very small indeed. You can define your own constants: 1960 constant yearofbirth Now whenever you enter the word "yearofbirth", the number 1960 will be put on the stack. However, when you quit BCL you will loose such definitions. Later, we will see how you can save them across BCL sessions. It is also possible to store numbers that may have to change in the future. Such numbers are stored in variables. A variable is created in a way similar to constants: 31 variable age However, since variables can change their value, using a variable requires that you indicate whether you want to read it's current value, or whether you want to give it a new value. For historical reasons (compatibility with forth), the word "!" is used to change the value of a variable (store), while the word "@" is used to recall the value of a variable. If you don't like these or other choices I have made for words, you can change them to anything you like. Just read section 3: customizing BCL. The next example shows how to create a variable, and store and recall values from it. In this and following examples, I will not show the symbols any more. Just remember to type one or more spaces or returns at the end of each word. Also, at some places I will put words between braces {} to add some comments. Don't type the braces or the comments! Comments are not implemented in this version of BCL. As for the example: 7 variable x x @ 3.15e2 x ! x @ You might have noticed that when a variable is executed (this is, when you hit the space bar following the x), a number appears on the stack which disappears when ! or @ is executed. This number is the address of the variable, and shouldn't be of much interest to you. In fact, if you would know what you were doing, you could store variables at any address by entering the address rather than the variable name in the example above. I'd much rather you wouldn't try, though, it's too easy to damage your BCL words. A special kind of variable is the array, which can be thought of as a one dimensional array or vector of numbers. The size of the array (rather than it's value) is defined in the creation of the array. The array is invoked in the same way as a variable using "!" and "@", but an additional modifier is used to indicate which element you want to store or recall. This modifier word is "[]". An example follows: 4 array a1 { create the array a1 with 4 elements } 1 a1 0 [] ! { store the number 1 at position 0 in a1 } 5 a1 1 [] ! { store the number 5 at position 1 in a1 } a1 0 [] @ { check that 1 is still there } a1 1 [] @ { check that 5 is still there } Be careful with the "[]" and "!" words. They will operate on anything, and do in fact not check that the argument on the stack is an array or even a variable. This completely your responsibility, and it is quite possible to mess up your BCL image this way. There is some protection against writing outside of the BCL image and damaging other files on your portfolio, but don't count on it too much yet. It is one of the latest additions to BCL and therefore not as thoroughly tested as I would have liked. In fact, I only included this protection so I wouldn't feel too guilty when releasing this program.... All variables (and in fact all numbers) in BCL are in 6 byte floating point format, with about 11 significant digits. When printing a variable, BCL will decide how to format it (as an integer, fraction or floating) depending on it's value, but the number itself is always a floating point. Thusfar, we have seen two ways to define new words in BCL, namely constants and variables. A third type of word is the macro. A macro can be thought of as a series of words which are automatically executed once you enter the name of the macro. Macros are words themselves, so you can use macros inside macros. Also, macros are implemented very efficiently, typically taking just one byte per word you enter. This allows for very efficient memory use and fast execution. Finally, inside macros a few words can be used which don't make much sense outside a macro definition, namely conditional and repetitive words. First let's look at a simple macro definition for a macro "abs" that computes the absolute value of a number on the stack by taking the square of the number and subsequently taking the square root: : abs sqr sqrt ; You will notice that the stack is not updated while defining a word. This was done because the compiler uses the stack and you might get confused when you would see all these strange numbers appearing and disappearing on the stack. At least, I got confused, so I disabled the display. An additional benefit is that now you can see the complete definition as you are typing it, without previous words and lines disappearing. If you make a typing mistake within a word, you can correct it using backspace. If you try to enter a word which does not exist, you get an error message, but the compilation of the word continues as if you never typed the offending word. The word ":" is used to start a definition, and the word ";" to terminate the definition of a macro. Immediately following the ":" is the name of the macro you are defining, followed by all words you want executed when you execute the macro. Let's try executing our new macro: -5 abs 4 abs All but the most trivial macros do require some way of controlling execution depending on the data entered. This is accomplished in most programming languages with conditional statements (if, then, else in pascal), repetion statements (repeat..until, while..do in pascal) or jumps (goto in basic). In bcl, two kinds of control are implemented currently. First let's look at conditional execution. As an example, we will implement a simple number guessing game, in which we assume that somebody else has entered a "secret" number in variable secret, and you are supposed to find it's value by executing the macro guess, which will respond to the number you have put on the stack by putting -1 (too low), 1 (too high) or 0 (right) on the stack. Of course, it is quite easy to cheat (can you type 'secret @'?) but that is not the point of the example. Let's get started: 738 variable secret : guess dup { duplicate the value on the stack } secret @ > if drop 1 { the guess was too high: leave "1" at the stack. No further test is required: drop the duplicate } else secret @ = if 0 { The guess was right: leave "0" at the stack } else -1 { If it ain't too high and it isn't right, chances are it's too low: leave a "-1" } endif endif ; As you can see from the example, you can compare the top two numbers on the stack using words like ">", "<", "=" etc. The result of the comparison (a "0" for false or a "1" for true) are left on the stack by such words. The word "if" can be used to execute the words between the "if" and matching "else" if the number on the stack was "1", or to execute the words between the "else" and the matching "endif" if the number on the stack was "0". The "else" part is optional, and, as you can see, "if" constructions can be nested. The second kind of execution control in BCL is the loop. This is used to execute words repeatedly, until some condition is met. An example is shown below: 0 variable loopindex : characters 65 loopindex ! repeat loopindex @ emit loopindex @ 1 + loopindex ! loopindex @ 90 = until ; The macro characters will display the alphabet on the display when executed. You will notice that immediately after completion, the screen will be repainted and the alphabet will disappear. This can be avoided by switching off the stack display. The word "noshow" will accomplish this, but the stack that was already on the display is then still visible. To work around this, we use the word "text", which will put the computer in text mode and in the process clear the screen. Now we can use the word "key" to read a single key from the keyboard and put it's ascii code on the stack. This is useful to e.g. have the computer wait until you press a key. Now let's combine all this into a new definition, called "chars": noshow : chars text characters key drop ; chars { press a key after the alphabet has been displayed } show The drop following the key will dispose of the ascii code on the stack, and the show will switch back on the stack display. In fact, within a single word stack display is suppressed anyway, so it is not really necessary to switch the stack display off in this case, but at least it is good to know that the possibility exists. When the stack is not displayed, you can print the number at the head of the stack by using the word "." This will also remove the head of the stack. Graphics can be accessed through the words "graphics" (put the computer in graphics mode), "point" (display a pixel) and "line" (display a line). The word "text" will put the computer back in text mode. For example: : testgraph graphics 50 50 point 20 30 200 40 line key drop text ; testgraph { hit a key when the dot & line have been displayed to return } You can use graphics also interactively, but you will notice that some computers, like the portfolio, will mess up the graphics screen when displaying the characters you are typing. At some point you may find that you made a mistake in a word, or that you don't need or want some definitions. It is possible to remove words from bcl by typing "forget" followed by the word you want to remove. However, all words defined following this word will also be removed, so be careful when using "forget". You can use "list" to find out which words have been defined, and in what sequence, so you can determine the effect of "forget" before you execute it. The main reason that all subsequent words are discarded is that it is rather difficult to find out whether a word has been used in subsequent definitions. If bcl would allow the removal of words which have been used elsewhere, the image would become inconsistent and very strange things might happen. Some mechanism to revise words which have been defined a long time ago without reentering all newer words again would be useful, especially when developing libraries that plot functions, or determine zeroes, derivatives, etc. because it is rather inconvenient to have to reload such a library each time you want to use another function. For this reason, the primitive "update" has been implemented. Basically, "update" replaces the definition of some old word by a newer definition. To replace the definition of some old word, let's say "not", we start with creating a new definition for not: : not 1 swap - ; Now we can try whether this new definition indeed performs as we like by executing it. We can even create new macros which use this new definition of "not", but all words defined before the new "not" will keep using the original definition. To replace the original definition of "not" by the new one, execute the word "update" after the new definition of "not", but BEFORE any subsequent words have been defined. This is necessary because "update" works on the newest word. After executing "update", you will find that the new "not" has taken the place of the original "not", i.e. when viewing the definitions in bcl (using "list") it has disappeared from the end of the list and is now in the position of the original "not". All words which refered to the original "not" now refer to the new definition. There is no limit as to the size of the new definition: it can be smaller or larger than the original definition. It might even be a different type of word, e.g. a variable of constant. This method is also useful to redefine constants. It can even be used to achieve an effect similar to recursive procedure calls or circular procedure calls, in a way very similar to the "forward" definition mechanism in pascal. For example: : x1 ; : x2 dup 0 > if x1 1 - dup . endif ; : x1 dup 0 > if x2 2 - dup . endif ; update Now "x1" and "x2" will call each other until the number on the stack becomes zero or negative. Be careful with this mechanism: a combination of "update" and "forget" can result in calls to non-existing words! (e.g. by executing "forget x2"). This cannot easily be overcome without adding much code to bcl, but fortunately in practice it isn't very likely to happen either. Therefore, I decided to leave this for the time being the way it is; just be aware that it is possible to create a mess this way. If you don't feel confident using both "update" and "forget", limit yourself to either one. All words that have been defined in BCL can be saved to a file using the word "save" followed by a file name. The file will contain a memory image of the user definable words in BCL, which is an extremely compact format for small programs. Typically, this is smaller than either the input in ascii format or a comparable program compiled by a standard compiler (e.g. pascal or c), because most of the functionality of a small program is in the primitives of the BCL machine, which are not saved because they cannot be changed by the user anyway. To save all your work thusfar, execute the following: save demo This will create a file demo.bcl in the current directory. To load this file in a future session with BCL, you can either start bcl using the command bcl demo or you can start in the normal way bcl std and execute from within bcl the command load demo You can make the image files (created with save) even smaller by eliminating all references to primitives you don't use (this can save several hundred bytes!). See section 3. If you want to make a complete application, e.g. to call from a batch file, you can give a 2nd argument to the bcl command which indicates which word should be executed after the image has been loaded. This can also be used to set some preferences (e.g. noshow, PointMode, etc). I have a batchfile b.bat set up which contains the single line bcl std initialize In the std.bcl image I included the word initialize which puts everything just the way I like it. This concludes the tutorial part of section 2. Below are some details on the parsing of words, and a list of all words in the standard image. The BCL Input format: A space or return will cause the preceeding word to be executed. Subsequent spaces or returns can be added to format the input, if so desired, but don't have any meaning. You can use the backspace key to change a word before it has been executed (i.e. before you hit the space bar or enter key). After the word has been executed, it cannot be changed any more, even if it still appears on the input line. If you try to do so anyway by backspacing beyond the start of the word you are currently entering, you will get the error message: "No input". Words can be either numbers (integers, fractions, or floating point numbers) or strings which have been defined in BCL. The rules for interpreting words are: 1. if the word has been defined in BCL, it is interpreted as this word 2. if the word has not been defined in BCL, but it has the correct format for a number, it is interpreted as a number 3. if the word has not been defined in BCL, and has not the correct format for a number, it is an error. This implies that you can redefine numbers by defining macros, variables or constants with a name equal to a number. This is indeed possible, and can be used to save space, because a word takes only one byte of code whereas a number takes 7. However, care must be taken that the words defined this way actually represent what they imply, otherwise unexpected results can occur. An example of what is possible, but not always useful: : 5 3 ; 5 sqr { result is 9!!! } Dictionary of BCL words: Words are shown in alphabetical order. The order in which they are shown with "list" is different and corresponds to the order in which they were defined. This is also the order in which they are stored in the image. Words are shown here with on the 1st line the word followed by the stack before execution (with each n representing a number), two dots, and the stack after execution of the word (with each n again representing a number) acs n1 .. n2 computes the inverse cosine of n1 and leaves the result as n2 on the stack allot n1 .. Leave n1 bytes empty space between the last defined word and the next word that will be defined. Useful for defining arrays and other data structures. arguments n .. Internal use only. Modifies the last defined word to have n arguments as inline code when compiled array n1 .. define a vector with n1 elements (0..n1-1) with a name identical to the next word typed on the keyboard. asn n1 .. n2 computes the inverse sine of n1 and leaves the result as n2 on the stack atn n1 .. n2 finds the arctangent of n1 and leaves result as n2. n2 is in rads chs n1 .. -n1 changes the sign of n1 and leaves the result as -n1 on the stack clr n1 n2 .. clear the stack constant n1 .. define a constant with value n1. The name of the constant is the word entered following constant cos n1 .. n2 computes the cosine of n1 and leaves the result as n2 on the stack drop n1 .. remove the number at the head of the stack dup n1 .. n1 n1 duplicate the number at the head of the stack else n1 .. n2 part of a "if ... else ... endif" construction. The words between if and else are executed only if a "1" was at the head of the stack when the "if" was encountered. Otherwise, the words between else and endif are executed. emit n1 .. display the character whose ascii value is n1 endif This word ends a list of conditionally executed words. This list should be started by the word if exp n1 .. n2 finds e to the power of n1 and leaves result as n2 forget forget all definitions defined since the word entered as the next word on the keyboard graphics switch computer display to graphics mode here .. n1 Leaves the address immediately following the last compiled word on the stack as n1 if This word starts a conditional statement of the form: "if ... endif" or: "if ... else ... endif" The words following "if" will only be executed if a "1" was at the head of the stack when executing the "if". The words following else will be executed if there was no "1" at the head of the stack. immediate Modifies the last defined word to execute always, even if used inside a macro definition initialize Clear the screen, switch of the stack display, and display a version header. inv n1 .. n2 computes the inverse of n1 (=1/n1) and leaves the result as n2 on the stack jmp n .. Internal use only This is an unconditional jump, which will be used by else in future releases jz n .. Internal use only This is a conditional jump, used by if, until etc. key .. n1 wait for a key to be pressed and put it's ascii value as n1 on the stack line n1 n2 n3 n4 .. display a line from x=n1, y=n2 to x=n3, y=n4. The line is displayed with the mode defined by PointMode list show a list of all the words defined in the current BCL image literal n .. Internal use only This is the word which is compiled when you type a number inside a macro ln n1 .. n2 compute the natural logarithm of n1 and leave the result as n2 load load the image file with name xxx.bcl, with xxx equal to the word entered following load log n1 .. n2 computes the 10 base logarithm of n1 and leaves the result as n2 on the stack noshow Switch off stack display until the word "show" is executed not n1 .. n2 if n1 is zero, n2 is one. If n1 not zero, n2 is zero. offset n1 .. n2 computes the size of n1 numbers in bytes and leaves it on the stack as n2 pi .. 3.1415926536 leaves an approximation for the number pi on the stack pi/2 .. n1 leaves a number n1 on the stack equal to half the value of pi PointMode n1 .. This word can be used to change the mode in which graphics are displayed. Useful values for n1 are: 0: points and lines are black (or white on an LCD screen) 1: points and lines are white (or black on an LCD screen) 129:points and lines are inverted (white becomes black and vice versa) point n1 n2 .. display the pixel at x=n1, y=n2. x=0, y=0 is upperleft corner. The pixel is displayed with the mode defined by PointMode primitive n1 .. create a word with a name equal to the word entered next on the keyboard. This word will, when executed, invoke primitive n1. quit quit bcl, return to dos. Forget all changes to the image. Can also be achieved by pressing the escape key repeat .. n1 start a loop control structure. Repeat all words between repeat and until as long as the condition before until evaluates to 1. In fact, this word leaves the current address on the stack for the compiler to use when compiling "until". It does not generate code itself. save save the image to a file with name xxx.bcl, with xxx equal to the word entered following save show starts displaying the stack after each word entered by the user sin n1 .. n2 finds the sine of n1 and leaves result as n2. n1 is in rads sqr n1 .. n2 computes the square of n1 (n1*n1) and leaves the result as n2 on the stack sqrt n1 .. n2 computes the square root of n1 and leaves the result as n2 on the stack swap n1 n2 .. n2 n1 exchange the top two items on the stack tan n1 .. n2 computes the tangent of n1 and leaves the result as n2 on the stack text switch computer display to text mode until n1 .. completion of repeat..until structure. Jump back to the matching repeat if a "1" is encountered on the stack. This word in fact compiles a "jz" with the address calculated from the n1 left on the stack by repeat. update .. If there is more than one word defined with the same name, replace the 1st word with this name with the last word defined with this name. This can be used to replace old definitions of macros or constants without having to "forget" and reenter all the words defined after it. variable n1 .. define a variable with initial value n1. The name of the variable is the word entered following variable version .. display a message identifying the program and it's version ! n1 n2 .. store the number n2 at the address of n1, which is typically put on the stack by executing a variable word * n1 n2 .. n3 finds the product of n1 and n2 and leaves the result as n3 + n1 n2 .. n3 finds the sum of n1 and n2 and leaves result as n3 - n1 n2 .. n3 finds the sum of n1 and n2 and leaves result as n3 . n1 .. Print the number at the head of the stack, removing it from the stack in the process : start a macro definition / n1 n2 .. n3 finds the quotient of n1 and n2 and leaves the result as n3 ; complete a macro definition < n1 n2 .. n3 This word will leave the number 0 as n3 on the stack if n1 >= n2, else it will leave the number 1 as n3 <= n1 n2 .. n3 This word will leave the number 0 as n3 on the stack if n1 > n2, else it will leave the number 1 as n3 <> n1 n2 .. n3 if n1 <> n2 then n3 is one, else n3 is zero = n1 n2 .. n3 Leave the number 0 as n3 if n1 is different from n2, otherwise leave the number 1 as n3 > n1 n2 .. n3 if n1 > n2 then n3 is one, else n3 is zero > n1 n2 .. n3 if n1 > n2 then n3 is one, else n3 is zero >= n1 n2 .. n3 if n1 >= n2 then n3 is one, else n3 is zero @ n1 .. n2 recall the number at address n1, and leave the result as n2. N1 is typically put on the stack by executing a variable word [] n1 n2 .. n3 finds the address of the n2th number of an array starting at address n1. N1 is typically obtained by entering the name of an array ^ n1 n2 .. n3 computes the power of n1 and n2 (n1^n2) and leaves the result as n2 on the stack These definitions can also be found in file bcl.adr in Portfolio address book format. 3. Customizing BCL When bcl is started without an image, it contains only a single word: primitive. This is in fact the fourth way to create new words in BCL, which I haven't mentioned yet to avoid confusion. The BCL machine contains the code for many (but not all) words in the standard bcl image. This code can be invoked by attaching a name to these pieces of code. This is accomplished by the word primitive. For example: 8 primitive plus will create a word plus which invokes the code in the BCL machine for the 8th primitive. This primitive is normally invoked through the word "+" and carries out an addition of the top two items of the stack. By starting out with an empty image, only those primitives needed for an application can be attached to words, and the words they become attached to can be chosen to your liking. This way, BCL can be changed beyond recognition. The basic principle of BCL, namely that it consists of single words which are defined in terms of primitives of the BCL machine, can of course not be changed this way, but the amount of customization possible is significant. Remember that all word names are also stored in the image. Long words increase the size of the image and require more typing. On the other hand, they will make programs more readable. The trade off is up to you. Some words of the standard image are defined as constants, variables and even macros. You can change these even more, or leave them out altogether. There are some limitations: literal has to be available if you want to use numbers in a macro definition, although it's name can be changed jmp and jz have to be available if you want to use if,then, repeat and until; again, their names can be changed. One way to create a new image is to look at file bcl.src, which contains all the definitions used to build the std.bcl image. If you like, you can start bcl without an image name, and start typing in the parts of and modifications to this file that you like, and save the image at the end. This is rather cumbersome. A more convenient way to build an image (and the method used by me) is to create the image in a file similar to bcl.src, and then execute bcl < bcl.src This will build the image, and, if you remember to put a save and quit instruction at the end, will actually create the image file for you. Have fun experimenting! 4. BCL Machine Limits The current release of BCL has the following limits: Maximum stack size: 20 numbers Screenheight: 8 lines Screenwidth: 40 characters Memory Size: 4096 bytes Max number of words: 256 Macro nesting levels: 40 These limits can be easily changed by changing some constants in the source code and recompiling. Feel free! 5. Future plans & improvements As soon as I have some spare time (what's that anyway?) I would like to extend BCL with the following features: - string support using an alphastack as used in e.g. polymath - math library with integrals, differentials, etc. - extending the plot library for plotting 3d functions - rebuild BCL from scratch as a full object oriented language which also allows symbolic math, similar to the HP48 Looking at my calendar, I would like to recommend not holding your breath until the next release. You might feel dizzy after a while... If anybody else is interested to carry out some of these projects, please feel free to contact me to obtain hints and good whishes. I am of course very interested in such extensions and derivatives. 6. Copyright This program is copyright (C) Peter Baltus, 1991. Anybody is welcome to use this program (BCL.EXE) in whatever way he or she likes, with the exception of selling the program. I do ask that, if you distribute BCL, you do it as a complete set with all its files, preferably in its original archived format. I do not accept any responsibility for anything that goes wrong, breaks, or otherwise causes you trouble in relation with this program, but I would very much like to be informed about any problems. I might even fix them, but, as I am sure you will understand, I cannot actually guarantee support for this price.... If you make any modifications to the program, or have any proposals for modifications, please let me know. I am very interested to hear how (or if) this program is being used. 7. Acknowledgements I would like to thank the following persons & companies for providing inspiration and for providing programs that were used to create & distribute BCL: Robert Young for his ARJ program which is used to create the self- extracting archive in which BCL is distributed Fabrice Bellard for his LZEXE program which is used to reduce the size of BCL.EXE Forth Interest Group for supporting the FORTH concept AcornSoft Limited for creating the implementation of FORTH that got me interested in threaded languages (ATOM FORTH) Lobster Software for creating a very extensive forth-based language for mathematical applications (POLYMATH) 8. Update history 1.1á September 15 1991 Initial release 1.3á October 27 1991 Added primitives for "else", "update", and "version" Removed copyright message at startup Added "initialize" in bcl.src Changed word search order, allowing newer definitions to override older ones Added memory used & memory left at end of "list" Added "plot.src" library for plotting & finding zeroes of functions Reformatted "bcl.adr" file for portfolio use Added comments to pascal source code & included this in release