This document gives you a broad overview of the more exotic features of Abundance. These exotic features must be understood as they are used in even the most mundane programs. This document is roughly what I submitted to Byte Magazine back in 1986-04. They edited it severely and published it in 1986-10. They own the copyright on both this version and the published version, so if you wish to publish any part of this, you will have to get permission from them.
Abundance is a Forth-based, data-entry, data-base and screen-handling language. It automatically handles the routine housekeeping that normally accounts for 90% of interactive application code. All Abundance programs can Jaunt — run backward in time. Abundance is not an acronym. It was originally designed to serve charities working to create an Abundance of food water and shelter on the planet; but because it has such an Abundance of features, it has now become an excellent business programming language.
Abundance is a rich language. It has 600 verbs of its own, 400 inherited from Forth-83, 300 inherited from assembler and 900 hidden verbs. Conventional wisdom posits that languages should be lean. For example Pascal has about 20 keywords. Working with lean computer languages is like speaking with someone who understands only 20 words of English. Even Esperanto, an artificial human language designed for simplicity, has 15,000 root words.
We would laugh at a robot that broke through a door simply because we forgot to tell it to open the door first. We expect robots to know that doors need opening. I think compilers should be equally brilliant and remember to do things without being explicitly asked to, such as opening files, validating data entry, converting values back and forth between binary and ASCII (American Standard Code for Information Interchange), keeping track of how many elements are used so far in an array, reading and writing to disk, or laying out fields in columns on the screen appropriately labeled. If I recompute a variable that happens to be currently displayed on the screen I expect the compiler to automatically refresh the screen with the new value just as a spreadsheet would.
I expect my compiler to understand the Zip Code system, the telephone numbering system and the States of the union; and be able to cross check all three. Furthermore, I expect my compiler to know this information not only for the USA, but for other countries as well. I want it to know that phone numbers need a dash in the middle and area codes are surrounded in parentheses. It should even know that 555-1212 is not the phone number of any real person.
I expect my compiler to know the calendar. It must know that 1900 was not a leap year and that 2000 will be. (Lotus take note!) It should know that the people in India use DD/MM/YY and Swedes use YY.MM.DD. But most of all, I want my compiler to take the initiative and use this knowledge without my having to explicitly ask it.
I expect it to understand the limitations, quirks and control sequences of at least 20 brands of printer. I don’t want to be bothered with such detail. As a programmer I want to pretend I have a perfect printer that can print in any pitch, in any typestyle, any of the 256 accented and special characters. I want to be able to use words like ITALIC, BOLD, WP-QUALITY and have the compiler do the best it can. (Windows has since taken over this task.) It should be able to number my pages 1 of 20.
I expect my compiler to speak to end users in English, French, Swedish or Esperanto. I should be able key all the accented characters without resorting to the numeric keypad. I want my compiler to be able to interface elegantly with other packages such as Btrieve, Lotus-123, VP-Planner, Microsoft Word Mail Merge, Ready!, Opt-Tech Sort, Superkey and Prokey.
Abundance is such a compiler. It has been performing these feats in a production environment since 1981. It handles the bulk of the programmer’s housekeeping chores implicitly. It does not use artificial intelligence techniques; it simply performs extra work as a side effect of the work you explicitly ask it to do. However, Abundance is not paternalistic. If you want explicit control of any of these housekeeping tasks, you can take as much control as you want. Because Abundance is a superset of both 8086 Assembler and 32-bit Forth-83 and because all the hidden verbs that form the compiler itself are always available, you can interface at any level you want.
Abundance was originally designed in 1981 for The Hunger Project in Canada, a charity committed to ending world hunger by the year 2000. Now charities in Australia, Canada, India, Sweden, and the USA are running public-domain custom-written Abundance application programs. Volunteers (including my 66-year-old mother) can do data entry into Abundance applications after only 5 minutes of training. The end user sees a traditional full-screen layout indistinguishable from one hand-crafted in C, sometimes with pretty boxes, but more commonly in columns or rows with data labeled with the corresponding variable names. Abundance makes full use of all the highlighting or color capabilities of the screen. Every time an Abundance application wants the user to keyin data, it highlights the field in inverse video and plops a oversized blinking cursor on the first character of the field. It then produces a uniform prompt message across the bottom two lines of the screen. The prompt always contains the name of the variable being keyed, the lower and upper acceptable bounds, (or a list of possible choices), what sort of data is wanted (a Name, a Zip Code, a date, a number, a dollar value etc.) and usually some additional explanatory information. In addition Abundance maintains CapsLock, Shift and Numeric keypad indicators.
The user can use the backspace, arrow keys and the function keys in a way that mimics his favorite word processor to edit the data. If he gets lost, he can hit the Oops key that puts the field back the way it was. Any errors in keying are usually detected the instant they are made. Abundance makes various polite sounds for different classes of warnings and errors. From these auditory clues the experienced user does not even have to look at the error messages to figure out what he did wrong. Abundance works in the background, hitting the shift key for the user when he forgets to, jumping over the dash in a phone number and keeping numbers right justified (calculator style) as they are entered.
If the user realises he should have entered some different value in a prior field, he can hit the Up-arrow key and make the program run backward in time. He can then enter a new value for the prior field and use the Down-arrow key to run the program forward in time and carry on where he left off. Later on in the article I will explain how this magical, but totally necessary feature, called jaunting is implemented. The user can also hit the Escape key at any time. In general this will cause the application to gracefully stop what it is doing in such a way that all files are logically consistent and no data are lost. Abundance was designed with the presumption the end user would be a naïve volunteer, but it is responsive enough that it can keep up with even the fastest professional data entry clerk.
Jaunting is the ability that all Abundance programs have to run backward in time. Jaunting sounds like an esoteric and frivolous feature, something I dreamt up after a late night TV Dr. Who marathon. A little history about the invention of jaunting may dispel this notion. I wrote Medics, a proprietary billing program for physicians to deal with the socialized medicine bureaucracy; as expected the data entry rules were Byzantine. I first considered the IBM (International Business Machines) Cobol or Macintosh Pascal approach, namely let the user wander all over the screen entering data in any order he wants, doing only minimal field edits. Only after he has entered a whole screenful of data, does the program perform the cross field checks and ensure all necessary fields have been entered. I rejected this approach because it was user-hostile, so I elected to use another approach favored by (shudder) Basic, namely lead the user by the hand field by field.
Then the embarrassment started. During a demo a doctor asked, "How do I go back two fields and enter 3333 instead of 100 for the Fee-Code field? I then had to humor" the computer by finishing off the current entry with dummy data. My extensive error checks beeped and blatted at me as I tried to drag the program around to a point where I could re-enter the Fee-Code field. Needless to say, the doctor did not buy the package. I needed a way of being able to easily back up two fields and keyin different data and then carry on where I had left off. The doctor knew computers were capable of such a triviality.
Jaunting was invented to solve this problem. I first invented a half-hearted form of jaunting similar to the one used by Forms-11 for the DEC (Digital Equipment Corporation) PDP-11. Abundance application constantly monitored whether the user had recently hit the Up-arrow key. When he hit the Up-arrow key the program jumped back to allow the user to rekey the previous field. This solved the problem for the user, but created a nightmare for the programmer. My source code turned into a rat’s nest of undebuggable backward branches and nested loops. To get around the problem of rat’s nest code, I invented true jaunting similar to the approach used in FDL (Forms Development Language) (Forms Development Language) that ran on the BMT (Burroughs Modular Terminal). Abundance application programs are written as though the user entered perfect data the first time every time. An Abundance application is perfectly unaware that sometimes it runs backwards in time.
Jaunting is simply a very streamlined version of the IBM OS/370 checkpointing facility. Every time the user keys in a field, the Abundance compiler secretly takes a snapshot of the state of the application program. When the user hits the Up-arrow key, the Abundance compiler finds the appropriate old snapshot of how the application used to look, inserts it as reality and wakes up the application. The application then carries on with amnesia as if it had never been any further than that. The implementation has no perceptible overhead. It is quick because there is no need to take a snapshot of all of RAM (Random Access Memory). Just the tiny Data Stack, the Return Stack and a few critical Abundance internal state variables need be saved. As all Forth programmers know, the Data Stack holds temporary variables and parameters passed to procedures; and the Return Stack keeps track of which procedure called which procedure. Surprisingly, the values of the variables are not saved as part of the snapshot. If the Abundance compiler did save the variables and then restored them to the old state after jaunting back in time, the end user would be furious because his newly entered data would have been thrown away. When an application program wakes up after its jaunt back in time, the values of the variables keyed just prior to jaunting are intact. You might think it would hopelessly confuse the application program to wake up after the jaunt and find the variables it is just about to request to be keyed are already entered, but in practice this rarely causes trouble.
Once jaunting was invented I discovered it had some wonderful fringe benefits. An Abundance application can assert that a certain expression just MUST be true no matter what e.g. that three fields simply have to add up to 100%. The Abundance compiler, on detecting that one of these MUSTs has failed, puts the blame on some earlier keyin and jaunts the program back in time to let the user have another go at keying the culprit field. The programmer can optionally give the compiler hints as to which field he thinks the culprit might be, but even if he guesses incorrectly, the user can use the Up and Down Arrow keys to correct the real culprit. There is a variant of the MUST called the WARN that makes an eh? noise (I am Canadian) and asks him to confirm that this unusual condition is indeed OK. If the user answers No, the program jaunts back in time just the way a MUST would. here is an example of an Abundance application program that uses jaunting and MUSTs. Jaunting allows you to exaustively test programs by exercising a bit of code, jaunt back a few steps and test another flow of control.
(Figure 1 Abundance ) ( This program queries your motives for joining a health club. ) ( It demonstrates the use of Jaunting back in time. ) ( Anything in parentheses is a comment ) ( Note : the space after the " is intentional! ). <<<DEFINE MFB CHOICE Sexual-Preference ME ( Must Enter ) M=prefer Males F=prefer Females B=prefer Both EXPLAIN ( Declare a 1-byte variable that can have only the ) ( values M F or B ) 0 100 SMALL %-For-Health What % of your reason for joining the club was to improve your health EXPLAIN ( declare a 1-byte numeric variable ) ( Abundance transparently enforces the ) ( limits 0..100 ) 0 100 SMALL %-For-The-Males What % of your reason for joining was to meet handsome males? EXPLAIN 0 100 SMALL %-For-The-Females What % of your reason for joining was to meet beautiful females? EXPLAIN DEFINE>>> <<< VALIDATE-Percentages ( a procedure to validate all three percentages. ) CULPRIT Sexual-Preference ( Hint to compiler that misunderstanding the sexual preference ) ( question is likely the culprit if any subsequent MUST fails.) FROM %-For-Health %-For-The-Males + %-For-The-Females + ( postfix addition leaves the sum on the stack ) 100 = ( postfix comparison operator leaves True if the sum=100 ) Percentages must add up to 100 MUST ( If MUST sees a false it jaunts back in time ) ( to where the culprit Sexual-Preference was keyed ) ( in the routine HEALTH-Club, [not to the CULPRIT statement] ) ( and issues the error message, otherwise it does nothing. ) ( The end user can go still further back in time than we ) ( take him, by hitting the Up arrow key. If we take him back ) ( too far, he can come forward in time by hitting the Down ) ( arrow key. ) >>> <<< HEALTH-Club ( The mainline procedure. ) ( At any point the end user can hit the Up-Arrow key and ) ( run the program back in time to the previous question. He ) ( can then answer differently.) ( Depending on how the end user answers the sexual ) ( preference question, he is asked different percentages ) KEYIN %-For-Health ( Abundance generates a prompt using the variable name ) ( %-For-Health, the EXPLAIN string " What % of your ) ( reason for joining the club was to improve your ) ( health" and the limits 0..100. It invokes a mini word ) ( processor to help the user enter the number. The ) ( number automatically stays right justified as it is ) ( entered. All conceivable validations are performed. ) ASK Sexual-Preference ( Similarly Abundance prompts for one of the letters ) ( M F or B leaving the result on the stack ) CASE ( examine character on the data stack ) _ M OF ( prefers males ) KEYIN %-For-The-Males CLEAR %-For-The-Females ENDOF _ F OF ( prefers females ) KEYIN %-For-The-Females CLEAR %-For-The-Males ENDOF _ B OF ( prefers both ) KEYIN %-For-The-Males %-For-The-Females ENDOF ENDCASE VALIDATE-Percentages ( invoke cross-field verification ) >>>
In a traditional programming language, for every ArrayOfRecords Xyou declare, you need to declare three other variables. ArrayMax M: the maximum size the array can ever be (usually a constant), ArrayHighWater N : the number of slots in the array currently containing data and ArrayIndex J: the element of the array we are currently working on. Then you refer to X(J) over and over again. You rarely use any other subscript other than (J). Every once in a while you do use some other index by mistake and then spend 3 days trying to find the bug in your program! You have to manually maintain ArrayHighWater N and make sure ArrayIndex J stays safely in bounds. You have to explicitly mention J and N in every FOR J := 1 TO N loop that runs through the elements of the array (yet another place for bugs to creep in.) Abundance’s approach is to dispense with all but the array index J. X N and M all go. Only J is used. Abundance invisibly maintains the ArrayHighWater N and corrals an errant index J back into bounds. There is no need to say (J), this is just presumed. There is no need to mention anything other than the Array index in a <<<FOR J loop since Abundance keeps track itself of the array high water mark. A program to handle a single record can be converted to handle an array of records simply by changing the declaration. No procedural code need be changed. All that need be added is one line of code to set the implicit subscript. The equivalent transformation in a Pascal program would change nearly every line of code. The best way to understand implicit subscripts is to scrutinize Figure 2.
( Figure 2 Abundance implied subscripts ) ( How Abundance uses implied subscripts in arrays. ) ( This program stores the Names and Birthdates of two ) ( dependent children in an array big enough to hold up to 15 ) ( dependents. Then it prints them out. ) <<<DEFINE 1 15 <<<FLEX Dependent-Number ( Declare an array with 0 to 15 elements ) ( indexed 1 .. 15 implicitly by Dependent-Number. ) ( Abundance transparently tracks the High ) ( Water mark of the implicit subscript.) ( This way it always knows how many of ) ( the 15 slots currently contain data. ) ( Abundance transparently enforces the limits ) ( 1 .. 15 on the implicit subscript. ) ( Note that the array itself does not have a ) ( name. ) 30 ULS Child’s-Name ( Declare a upper/lower case string variable ) ( as one of the elements of the array. ) ( Abundance transparently enforces a ) ( no-accented-characters rule. ) 1950 01 01 JULIAN ( lower bound ) Today ( upper bound ) MMDDYY Child’s-BirthDate ( Declare a date variable ) ( as one of the elements of the array. ) ( Displayed as MM/DD/YY externally, but stored ) ( as a 16-bit unsigned Julian Date internally. ) ( Abundance transparently enforces the upper ) ( and lower bounds and date validity. ) FLEX>>> ( marks end of array ) DEFINE>>> <<< SETUP-Dependents ( procedure to initialize the elements of the array ) 1 TO Dependent-Number ( set the implicit subscript ) Bruce TO Child’s-Name ( implied [1] subscript ) 1954 03 26 JULIAN TO Child’s-BirthDate 2 TO Dependent-Number Brock TO Child’s-Name ( implied [2] subscript ) 1961 07 18 JULIAN TO Child’s-BirthDate >>> <<< PRINT-Dependents ( procedure to print all existing dependents ) EJECT ( start a fresh page if not on one already ) <<<FOR Dependent-Number ( Loop to run through all existing dependents. ) ( Abundance has transparently tracked the highwater mark ) ( so it knows the loop should run from 1 .. 2. ) ( Each time through the loop <<<FOR ) ( increments the implicit subscript Dependent-Number ) WRITE Dependent-Number SPACE Child’s-BirthDate 2 SPACES Child’s-Name NL ( implied [Dependent-Number] subscripts ) ( From the variable declarations, Abundance knows how ) ( to format the printout.) FOR>>> EJECT ( start a fresh page ) >>> <<< DEPEND ( mainline procedure to initialize and print ) SETUP-Dependents PRINT-Dependents >>>
To an Abundance application, a file is just a big array that is a little too fat to fit in RAM. You as a programmer read and write the records simply by changing the implicit array subscript which indexes which record you want to work on. Smalltalk style, Abundance automatically handles blocking and deblocking, reading, writing, opening, closing, caching and dirty bits. Abundance does everything it can to avoid doing physical disk I/O. Abundance handles standard DOS (Disk Operating System) files with fixed length records, but it has other tricks up its sleeve if you want higher performance. The program in Figure 2 can be converted to one that keeps the data in a file instead of an array simply by changing the word <<<FLEX to <<<SEQ and adding an external DOS file name and logical record length. i.e. C:Dep.Dat 256 1 15 <<<SEQ Dependent-Number. The equivalent changes to Pascal program would necessitate a complete rewrite.
( Figure 4 How to handle arrays/files in Abundance ) ( How Abundance uses Implied subscripts to handle files. ) ( This program stores the Names and Birthdates of two ) ( dependent children in a standard DOS file allowed to grow ) ( big enough to hold up to 15 dependents. ) ( Then it prints them out. ) <<<DEFINE C:Dep.Dat ( external file name ) 32 ( logical record size in bytes ) ( Usually you would leave room ) ( for new fields to be added in place ) 1 15 <<<SEQ Dependent-Number ( Declare a file with 0 to 15 records ) ( indexed 1 .. 15 implicitly by Dependent-Number. ) ( Note that the File itself does not have a ) ( name. ) 30 ULS Child’s-Name 1950 01 01 JULIAN ( lower bound ) Today ( upper bound ) MMDDYY Child’s-BirthDate SEQ>>> DEFINE>>> <<< SETUP-Dependents ( procedure to initialize the elements of the array ) 1 TO Dependent-Number ( as a side effect record 1 is read ) Bruce TO Child’s-Name ( as a side effect, record 1 is marked Dirty ) ( Abundance thus knows to write it sometime later. ) 1954 03 26 JULIAN TO Child’s-BirthDate 2 TO Dependent-Number ( as a side effect record 1 is written and 2 is read ) 1961 07 18 JULIAN TO Child’s-BirthDate Brock TO Child’s-Name >>> <<< PRINT-Dependents ( procedure to print all existing dependents ) EJECT <<<FOR Dependent-Number ( as a side effect, the appropriate record is read ) WRITE Dependent-Number SPACE Child’s-BirthDate 2 SPACES Child’s-Name NL FOR>>> EJECT >>> <<< DEPEND ( mainline procedure to initialize and print ) SETUP-Dependents PRINT-Dependents >>>
{ Figure 3 Abundance Pascal Arrays } Program Depend; { How Pascal uses explicit subscripts in arrays } { This program stores the Names and Birthdates of two } { dependent children in an array big enough to hold up to 15 } { dependents. Then it prints them out. } Const MaxDependents = 15; { the maximum number of dependents we could ever possibly have } Type Dependent = Record ChildsName : String[30]; ChildsBirthDate : Packed Array [1 .. 8] OF Char { stored MM/DD/YY as character } { should be between 1950 Jan 01 and Today } { this program does not enforce this } End; { Record } Var HighWaterDependents : 0 .. MaxDependents; { how many dependents we currently have } DependentNumber : 1 .. MaxDependents; { index of the dependent we are looking at now } Dependents : Array [1 .. MaxDependents] of Dependent; Procedure MaintainHighWater; Begin { corral a bad subscript back safely in bounds } If DependentNumber < 1 Then DependentNumber := 1; If DependentNumber > MaxDependents Then DependentNumber := MaxDependents; { Keep track of the largest subscript used so far } If DependentNumber > HighWaterDependents Then HighWaterDependents := DependentNumber End; { MaintainHighWater } Procedure SetupDependents; Begin DependentNumber := 1; MaintainHighWater; Dependents [DependentNumber].ChildsName := 'Bruce'; Dependents [DependentNumber].ChildsBirthDate := '03/26/54'; DependentNumber := 2; MaintainHighWater; Dependents [DependentNumber].ChildsName := 'Brock'; Dependents [DependentNumber].ChildsBirthDate := '31/12/61' End { SetupDependents }; Procedure PrintDependents; Begin For DependentNumber := 1 To HighWaterDependents DO Begin Writeln (Lst,DependentNumber:2, ' ', Dependents [DependentNumber].ChildsBirthDate, ' ', Dependents [DependentNumber].ChildsName) End; { For } Write(Lst, Char(12)) { eject the paper — works on most printers } End; { PrintDependents } Begin { Depend } HighWaterDependents := 0; SetupDependents; PrintDependents End. { Depend }
{ Figure 5 pascal files }
Program Depend;
{ How Pascal uses explicit seeks/reads/writes to handle files. }
{ This program stores the Names and Birthdates of two }
{ dependent children in a standard DOS
file allowed to grow }
{ big enough to hold up to 15 dependents. }
{ Then it prints them out. }
Const MaxDependents = 15;
{ the maximum number of dependents we could ever possibly have }
Type
Dependent =
Record
ChildsName : String[30];
ChildsBirthDate : Packed Array [1 .. 8] OF Char
{ stored MM/DD/YY as character }
{ should be between 1950 Jan 01 and Today }
{ this program does not enforce this }
End; { Record }
Var
HighWaterDependents : 0 .. MaxDependents;
{ how many dependents we currently have }
DependentNumber : 1 .. MaxDependents;
{ index of the dependent we are looking at now }
ADependent : Dependent;
{ working storage record for current dependent }
Dependents : File of Dependent;
Procedure MaintainHighWater;
Begin
{ corral a bad subscript back safely in bounds }
If DependentNumber < 1
Then DependentNumber := 1;
If DependentNumber > MaxDependents
Then DependentNumber := MaxDependents;
{ Keep track of the largest subscript used so far }
If DependentNumber > HighWaterDependents
Then HighWaterDependents := DependentNumber
End; { MaintainHighWater }
Procedure ReadRecord;
{ reads record indexed by DependentNumber into ADependent }
Begin
MaintainHighWater;
If DependentNumber > FileSize (Dependents)
Then { Record does not yet exist — fake it }
Begin
ADependent.ChildsName := ' ';
ADependent.ChildsBirthDate := ' '
End
Else { Record already exists }
Begin
Seek (Dependents, DependentNumber-1);
Read (Dependents, ADependent)
End
End; { ReadRecord }
Procedure WriteRecord;
{ writes record indexed by DependentNumber from ADependent }
Begin
MaintainHighWater;
Seek (Dependents,DependentNumber-1);
Write (Dependents,ADependent)
End; { WriteRecord }
Procedure SetupDependents;
Begin
DependentNumber := 1;
ReadRecord;
ADependent.ChildsName := 'Bruce';
ADependent.ChildsBirthDate := '03/26/54';
WriteRecord;
DependentNumber := 2;
ReadRecord;
ADependent.ChildsName := 'Brock';
ADependent.ChildsBirthDate := '18/07/61';
WriteRecord
End { SetupDependents };
Procedure PrintDependents;
Begin
For DependentNumber := 1 To HighWaterDependents DO
Begin
ReadRecord;
Writeln (Lst,DependentNumber:2, ' ',
ADependent.ChildsBirthDate, ' ',
ADependent.ChildsName)
End; { For }
Write(Lst, Char(12)) { eject the paper — works on most printers }
End; { PrintDependents }
Begin { Depend }
HighWaterDependents := 0;
Assign (Dependents,'C:Dep.Dat');
Reset (Dependents);
SetupDependents;
PrintDependents;
Close (Dependents)
End. { Depend }
There is never enough room on the screen to simultaneously display everything you want to show. You may only have room to show the detail of 4 transactions, when you would like to show 40. You need to be able to scroll so that you show any of the 40, but only 4 at a time. In traditional languages handling this scrolling is very complex. Scaffolds come to the rescue. All the programmer has to do is write the name of a particular scaffold as part of the declaration of a variable element in an array. Scaffolds might be names such as 2x6 for two rows of six columns, or 4Deep for rows with a maximum 4 elements at a time displayed. From then on Abundance monitors the implicit subscript of the array. It makes sure that the current element is always visible on the screen. As the subscript changes, Abundance scrolls the display as a side effect so that the end user can always see the current element, some preceding and some succeeding elements of the array. Other than the declaration, the application code is totally unaware that this scrolling is going on. It simply comes out in the wash that the element of the array you are keying or computing is always visible. Scaffolds can be any shape you have the mathematical ingenuity to describe — not just simple rowed windows.
This article has barely touched on the main features of Abundance. Abundance has scores of other novel features with colorful names like humps, jives, combos, anchors, gauntlets, living fields, fast forwards, variable variables (note to editor: Yes you read it correctly variable variables), moods, promises, safes, riktnummers and graceful bailouts. It even uses a number of four-letter verbs of Anglo-Saxon origin.
If you want to experiment with Abundance you will need Microsoft or IBM PC (Personal Computer) DOS 3.2 or later running on an IBM PC, XT or AT (Advanced Technology) or a close clone. You will need at least 384K of RAM and a hard disk. The applications you write can run on floppy disk systems however
I am no longer shipping Abundance. You would have to get a copy elsewhere. It is still running in production though I am gradually moving Abundance apps to SQL/Java so that they can be maintained by other programmers after I die.
Abundance source and documentation comes diskettes in IBM Backup/Restore format. You are strongly encouraged to copy the diskettes and give them away to your friends. There are no restrictions on how you may use Abundance, other than that you may not use it for any military purpose. You can create your own dialects of Abundance, sell it, or cannibalize it. The source code and machine-readable documentation includes:- Source code for the BBL (Big Black Lady) 32-bit Forth compiler written in Microsoft Assembler. BBL uses absolute Segment:Offset addressing for speed and hashed dictionaries for fast compilation.- Source code for PASM, a Post Fix Forth-style assembler written in BBL Forth.- Source code for Ned, a Forth-style full-screen source-code editor written in BBL Forth. It uses two monitors simultaneously if you have them. — Source code for the Abundance compiler written in BBL Forth.- Source code for some sample applications written in Abundance. They allow you to maintain a mailing list with extract, sort and print.- Machine readable documentation and tutorials in both Microsoft Word and vanilla DOS text file format.- Btrieve Run-time package.- a list of technical questions and answers submitted by Abundance programmers.- QDOS-II, a text editor and utility to browse, copy and delete files.- miscellaneous other useful public domain and shareware utilities.
Sooner or later you will want an assembler such as Microsoft Assembler or Optasm to generate customized versions of the BBL Forth compiler. To edit the assembler source code you will need a text editor such as the Norton Editor. Although you can get by without one, I would strongly recommend buying a keyboard enhancer such as Superkey or Prokey for editing Abundance source code. If you want to be able to do large external sorts, you will need Opt-Tech Data Sort. If you want Btrees (lookup by name as well as account number) then you will need Btrieve. If you want to do form letters, you will need Microsoft Word version 3. The pretty version of the Abundance documentation comes in Microsoft Word format. If you have an existing large database, then Ready! lets you semi-automatically re-key it into your new Abundance application though the improved edit checks. While you are waiting for Abundance to arrive in the mail, pick up a copy of Leo Brodie’s book Starting Forth and a 16-bit Forth compiler. You will need to learn Forth before you learn Abundance. Get the new Forth-83 revision of his book rather than the older Forth 79 version.
This page is posted |
http://mindprod.com/jgloss/abundance.html | |
Optional Replicator mirror
|
J:\mindprod\jgloss\abundance.html | |
Please read the feedback from other visitors,
or send your own feedback about the site. Contact Roedy. Please feel free to link to this page without explicit permission. | ||
Canadian
Mind
Products
IP:[65.110.21.43] Your face IP:[18.222.119.27] |
| |
Feedback |
You are visitor number | |