dib manual
(deer project, 2008, Antonio Maschio @ )
Last updated: December 05, 2008
This is not a BASIC primer, but the user manual of dib, the Dartmouth BASIC
interpreter written in C for the gcc.
Index
-----
0. A foreword
1. A bit of personal history as introduction
2. The dib interpreter
2.1 Origins
2.2 dib's invoking options
2.2.1 Options explained
2.2.2 Customizable items
2.3 A datum is a datum is a datum...
2.4 Default features
2.5 Extended features
2.6 Error messages
2.6.1 standard error messages
2.6.2 extended error warnings
2.6.3 system error messages
2.7 The examples
2.8 The vim 'bs' syntax file
2.8.1 Installing dib.vim
2.8.2 Mapping the dib syntax
3. Conclusions
4. Bibliography
-----------------------------------------------------------------------------
0. A FOREWORD
----------
Sometimes I read on some mailing list about programming, or on newsgroups
dealing with this or that programming language, or on specific programmers'
web pages, that "BASIC was a primitive language"; well, this may be true, in
some arcane sense, especially if you consider some modern complicated language
like java, C++ or Delphi or peculiar languages such as Prolog, Lisp, Forth.
But I contest this sentence 1) because BASIC 'was' not, BASIC 'is'; 2) because
BASIC is not primitive: it's simple. It's a rather different question.
Imagine you have to solve a math problem, say a system of linear equations,
and suppose you've got to write a program for this; which language will you
choose? Your 'favorite' may be too big for such task. Well, in the best case
you know this language very well, and you will end up without spending hours
in writing the program, but in the worst case you're lucky if you have not to
plunge into a 1000 pages user manual or learn tens of system calls.
Why not using Dartmouth BASIC? No more than a bunch of lines (containing even
the problem data) and the solution is there. No manuals, no system calls.
Yes, BASIC is an unstructured language - and someone said that a programmer
exposed to BASIC is likely to never learn well another language (this ain't
true, obviously) - so I guess that, if BASIC is unstructured, it expects you
to give it a structure. And the structure you create may make it spaghetti-code
looking, or make a superb listing of it. Dartmouth BASIC gives you two dozens
of statements and a consistent way to use them. It gives you a simple structure
for each statement and you have to build a wider structure for your program.
It's up to you: BASIC has no soul, it waits for you to give it one.
After all, BASIC is a language that can be used by anyone, that won't force you
to format numbers output, that uses matrices like numbers, that solves systems
of equations in a bunch of statements, that remains familiar and usable for
years. Some of us wouldn't ask for more.
Yes, using such a language today is quite unrealistic. I had to write my own
interpreter to do it, and this is not what I call a friendly way.
But hail to those guys who conceived such a language in 1964!!
1. A BIT OF PERSONAL HISTORY AS INTRODUCTION
-----------------------------------------
In the fall of 1980 I was fourteen, and I began my High School. A schoolmate,
who had later to became my best friend, received a magnificent Commodore 64
with monitor for Christmas, or so. For the rest of that year, and the following
1981, I tried to convince my parents of the extraordinary need I had for such a
computer and that I couldn't even imagine how to get through University without
it! Lost words. My father, whose sight was very long, told me he could get his
High School degree with a 5 inches slide-rule. Thus, a computer was not a need.
What could I do? I spent a lot of time in my friend's room, staring at the
wonderful colors of the screen, and learning my first BASIC words while
listening to him reading sources and watching him typing commands. Once back
home, the only way to relax was playing my guitar, because even my calculator
was not programmable. I was in a sort of "need of programming"...
Anyway, in 1982, my father finally made me a gift for my 16th birthday:
the CBM64! I wasn't surprised at all, since I think I had stressed him a lot
for that (in Italy, those were the days of microcomputers, and first computer
magazines - BIT, Microcomputer, and others - each full of listings in BASIC for
this or that computer, were flourishing in our newsstands, fighting a sort of
battle of the dwarves between the CBM64 and the ZX Spectrum).
The first thing I wrote was a program to draw a function y=f(x) in the
Cartesian space, plotted in high resolution on the screen (I'm afraid I was
not so smart to do it all alone: probably, I took the original source from a
magazine and changed it a bit). Anyway, the pride I felt showing the results
to my father pushed me to learn more about programming; I bought then the C64
monitor, the 1541 disk drive and [4].
I began studying [4], learning that machine language was available through some
hacking, learning about sprites, the three independent music oscillators (a
system called SID), all the peculiar memory addresses, but I didn't go beyond
BASIC for two reasons: first, machine language seemed to me too difficult and
strange and second, I thought BASIC was a wonderful language to do quite
everything (though programs ran slowly!). I bought then [3] and began studying
it seriously. The book was very professional, and all (or quite so) was
applicable to my home computer, so I felt like a very mature programmer! One
thing baffled me: the fact that all MAT statements were completely missing
from my home computer, while I was sure it was more recent than the one
described in the book!
In 1985 I began my University years, and for many years I couldn't do anything
else with the Commodore unit. I studied Pascal and Fortran 77, using the VAX
mainframe of the University Calculus Room, equipped with UNIX (circa 1987-88);
much later, I could use PCs with DOS (circa 1990-91, I believe version 2.x),
and so the CBM64 was left behind, with all its power. At home, abandoned, the
C64 went ruined, and one day my mother got rid of it without even telling me.
The day I knew what happened was a very sad day!
In 1993 my parents bought me a PC with Windows 3.11: it served me to do some
word processing for my thesis, but it was also a starting point in serious
computing. When I finally got my degree in civil engineering, in 1994, I began
working, and years began to fly.
In 1998 I installed linux on my PC and began studying C, bash and prolog, and
BASIC was not in my mind. So I lost any contact with it: line numbering, GOTOs,
the absence of specific functions and procedure calls, and other minor things,
confronted to the "new" languages I was learning, led me to forget BASIC,
because it was old.
*** ***
Time takes its time to work, but it works. In the summer of 2004, I visited Ron
Nicholson's site by chance, and discovered his chipmunk basic interpreter.
Ah!: BASIC was not dead, after all!
Next, reading some documents found in Internet ([1] in particular) I learned
that BASIC was born in the Dartmouth College in 1964 (many years before C!),
that its first versions were compiled and that they dealt with matrices (a
feature that was stripped from all subsequent BASICs). These facts were so
appalling that I took the C64 manual and the Gottfried book out of their dust;
reading them again revealed me one mere thing: I didn't cease to love BASIC.
Next step was conceiving a BASIC interpreter on my own, to be developed on my
brand new emac 1.42 equipped with Mac OS X. Why not? There are dozens of
compilers and interpreters in the world, one more will do no harm. The reason
that led me to forget BASIC is now the reason that leads me to love it:
because it's old!
2. THE dib INTERPRETER
-------------------
2.1 ORIGINS
-------
Development step #0: deer
Well, even before there was a minimal BASIC interpreter to work with, I began
working on the Operating System Emulator, deer. The name popped up all alone
even since, and was never changed. The fact I used bash for it is no surprise:
what language has such facilities to deal with strings? And what should I deal
with? Strings.
So bash was a natural choice (even if my second thought was to use C or java -
it's still hanging around my brain). The emulator came out evening after
evening, in a very natural way, and soon I realized I had a working environment
but no interpreter to test it. That's why, after quite a year, I left deer
behind and looked around for ideas on how to build my own BASIC interpreter.
During the following steps I've never ceased to carve and smooth deer code,
adding commands and beautifying code here and there.
Development step #1: dbasic3
The first conception of the interpreter was named dbasic3, because I meant to
write a Dartmouth BASIC interpreter version III. After a few weeks, I had
written nothing more than an engine(called version 0.1) to read file lines and
execute them directly, and some code for GOTO, GOSUB..RETURN, FOR..TO..NEXT and
END. I had some ideas on how to store source code lines (through malloc) but
the algebraic parser was still beyond my power.
So I started looking around, and one day, surfing in Ron Nicholson's site (the
author of Chipmunk BASIC) I found a reference to dds_basic, an appalling tiny
BASIC interpreter written in obfuscated C as Public Domain by Diomidis
Spinellis, a Greek guru who won the 1991 International Obfuscated C Code
Contest (http://www.ioccc.org/all/summary.txt) with such program. ds_basic
has the following features:
* it's interactive (OLD, NEW, RUN, SAVE...)
* it deals with integers
* it has the four basic operators (+,-,/,*)
* it has one-letter variables A..Z
* it's got a complete minimal set of statements
(FOR..TO, GOSUB..RETURN, GOTO, END, INPUT, PRINT)
* it doesn't do any error check; as long as sources are correct,
it's fast and furious.
* it's, with a source code less than 1000 characters long, amazing!
After decoding the dds_basic.c source file, I analyzed the whole code, and
boys if I was astonished! I made up my mind and stopped version 0.1 because
I wanted to integrate dds_basic into my code.
After introducing some of dds:basic features into my version 0.1, I renamed it
0.2 (it was still interactive), and enhanced some of dds_basic features (real
numbers, variables A0..Z9, some add-ons here and there and many many scattered
TODOs).
Development step #2: dbasic
Version 0.2 was a first step, but I wanted to build my own software, leaving
little of Spinellis' code into my own: so I decided to discard this version
and build up a new revision, 0.3, which could benefit from the parser and other
functions by dds_basic, while the rest had to be written by me. I decided to
make it non-interactive, because I wanted a real UNIX program. So I wrote only
the code for reading lines and executing them. I imported the primitives I
created for version 0.1, completed them with PRINT (still rough), DATA, READ,
IF..THEN, INPUT, DEF (a draft), and set up a minimal expandable error detecting
system. Version 0.3 was ready. I renamed it dbasic, because I thought version
III was beyond my power, so I arranged for a generic Dartmouth BASIC emulator.
Next versions 0.4 and 0.5 were nothing more than improvements over this 0.3,
but each featured an indecent numbers of bugs corrections. In particular, 0.5
was the first to incorporate the DIM statement, and the first to feature the
header file dbasic.h.
(From time to time, when I speak to myself, I call my BASIC interpreter dbasic. This name was THE name. Read on.)
Development step #3: db66
One day, I suddenly realized with pain that another dbasic was around on the
Internet, and I had to change its name. I hurryingly chose db66, because now I
had clear in mind that I wanted to emulate version III of the original
Dartmouth BASIC at all costs, because it was the first with a decent minimal
commands set, even if I had no idea on how doing it. And since it and I were
both born in 1966, db66 sounded good. But, in all, I didn't like this name
that much.
In any case, this newly name baptised version 0.6, which was nothing more than
version 0.5 with an improved mechanism to assign values to array variables;
next version, 0.7, was the first to incorporate the MAT statements (while
still... yes, buggy). In any case I'm particularly pride of the MAT INV
statement, which I built diving again into matrix theory, something I liked a
lot. The whole commands of version 0.7 worked well with correct BASIC programs,
but I couldn't care much of the error system, yet. Things were about to change
anyway...
Development step # 4: dib
Once version 0.7 was ready, I settled down a bit and decided to reconsider the
project name. db66 was not what I was looking for. So I began thinking:
This is a GNU project.
What does GNU mean? Gnu's Not Unix.
A recursive name? Let's try.
The first letter is a... 'd' (from Dartmouth)
So it should sound like... d*** does something, or d*** is something.
d*** is BASIC.
d-i-b. dib is BASIC.
Voilą, the name dib was born. It's simple, it's short, it fits perfectly in the
UNIX style, and above all, it's unique. I later realized that dib could also
mean "Dartmouth invented BASIC", as an homage to those two great men in
Dartmouth and to all Kemeny's kids.
Version 0.8, which consisted of an improved and debugged 0.7 version (you
cannot imagine how many bugs were still present...), with some enhancement
(for instance the DEF statement was rewritten) was the first to exhibit the
'dib' name.
Next version 0.9 (later renumbered 0.9a) was the first to implement a complete
revised error system, and the first to be fed with wrong BASIC programs, to
test all the error conditions I could conceive. Again, an incredible number of
bugs were corrected, leaving me the feeling I'll never end up with them...
Besides, I completely rewrote the parser, with an algorithm I conceived to
realize the algebraic-to-RPN conversion technique. I'm proud of this, because
it works well and it's robust.
During this development step I began writing down a number of programs and
transcribing examples from the 1964 manual or from the 1974 Gottfried book,
to be put into dib's package, and began even writing down the manual.
Just before releasing the alpha version, I realized many inconsistencies were
still present (bugs dealing with extremely rare conditions, rather than with
default behaviors), and so I got through a heavy testing., which enhanced a
curious fact: for each bug resolved, two arose. Will I ever end up with it?
I also incorporated the GPL3 default statements to the project. Finally,
version 1.0 alpha was ready to be turned to beta...
Development step #5: dib beta version
When I finally discovered what I thought was the last bug even in this beta
(the last in a temporal meaning, of course: many are still there and wait for
you to bring them up to surface, that's sure!), and after the very last touch
to the number output function, for a more complete conforming to the Dartmouth
BASIC output, dib was born, and began seeing the real world!
*** ***
Two texts were then fundamental: [1], that was important to target the output
for the PRINT statement and to set up all default features; and [2], that
helped me to clear all the differences among the six versions, and set up the
extended features.
*** ***
dib is part of the Dartmouth Environment Elementary Renderer package (deer).
2.2 dib'S INVOKING OPTIONS
----------------------
dib must be invoked with the following syntax:
$ dib [options] file
Options are:
-b Set array base index to 1 (default is 0)
-c Continue execution in case of non-blocking errors
--conditions Print redistribution conditions from GPL3
-d Activate debug mode
-h, --help Display this information and exit
-l Display error list and exit
-t Print a time report after execution
-v, --version Display version and exit
--warranty Print warranty conditions from GPL3
-x Toggle extended BASIC features setting (default is off)
-z Print numbers lower than 1E-10 as zero
A version of this paragraph appears when dib is invoked as dib -h.
2.2.1 OPTIONS EXPLAINED
-----------------
-b: sets option base to 1; at start, dib has a default 0 index base. In
extended mode you can set option base to 1 with the OPTION BASE 1
statement, which is not available in default mode.
-c: after an error, generally dib stops and prints a message; if you want it
to go on, activate this option, but **at your risk**! In fact, the program
may call variables not instantiated, or execute jumps or math expressions
with values not correctly initialized, so a system error (like
"segmentation fault" or "BUS error") may appear onto you terminal.
See paragraph 2.6.
-d: activate debug mode; when debug mode is on, the current line is printed
before it is executed; this of course alters the output behavior, but you
can trace the program flow, and maybe understand why your BASIC code is not
working.
Note: in extended mode, the final line containing END is not required by
a source file (see ahead); but, in order for the parser to work, if no END
is met into the source code, a superimposed END statement is implicitly put
at line 119881 (one above last available line), and this line appears in
the debugging session, even if the programmer doesn't expect it.
-h; print the standard UNIX help and exit (also --help).
-l: print the whole error messages list with the relative error code end exit;
since a system error causes dib to exit with 100+error code, you can get
this exit status in a shell program, and recover the error code active when
dib was interrupted. If you forget what error message is associated to a
particular error code, here's the -l option coming in handy. No program is
executed.
-t: after the program is terminated, print a timer report in the form:
TIME: N SECS.
where N is the number of seconds execution took (generally zero). It is
in the style of the 1964 Dartmouth BASIC manual (see for instance p. 19).
The time (in seconds) is taken starting from the beginning of the BASIC
code to its mere end, letting out all dib's set-up routines; this results
in a pure "BASIC code execution time". No conversion to minutes or hours is
done if the execution time is longer than 60.
-v; print the standard UNIX version banner, and exit (also --version).
-x: this option enables the extended features. See paragraph 2.5.
-z: all numbers lower than 1E-10 are printed as zero, useful when they may
clutter the output, e.g. with matrices. In this case, you can distinguish
"pure" zeroes from these approximations because the latter are always
preceded by their sign, positive or negative, so that 0 means a zero as
calculated by dib, -0 means an approximation (for instance -2.3E-14) as
does +0 (for instance 2.3E-14); you can change the limit of 1E-10 changing
the EPSILON constant in dib.h.
To know terms of warranty and conditions, type 'dib --warranty' and
'dib --conditions' (these commands print extracts of license, as required
by the GPL v3).
2.2.2 CUSTOMIZABLE ITEMS
------------------
In the file dib.h there are some values you can safely change to suit dib to
your needs:
- 'ef' is the variable flag that controls extended features activation; it's by
default FALSE; you can change it to TRUE to have extended features always
activated; if you do it, option -x will disable extended features, rather
than enable them.
- 'ob' is the option base index; it's by default 0; you can change it to 1
if you want to have option base index always starting from 1; if you do,
option -b will have no effect, and the only way to set option base 0 from
here is using OPTION BASE 0 in extended mode.
- 'false_' (mind the final underscore) is the flag that controls error
short-circuit; by default it's TRUE, which means that dib stops at every
error met; if you set it to FALSE, dib will stop only when a blocking
error is met (see ahead); if you do it, option -c will set false_ to TRUE
rather than setting it to FALSE.
- 'EPSILON' is the limit for numbers to be printed as zero. By default it is
1E-10, so that all numbers lower than EPSILON are printed as zero; you can
put here any value you like, provided it's not lower than 1E-75, which is
the lowest number for dib distinguishable from zero.
Don't change other variables, parameters, constants: you may mess up things
and end up with an useless program.
2.3 A DATUM IS A DATUM IS A DATUM...
--------------------------------
Numbers
-------
As the original BASIC, dib deals with a single number type: real. Any number
is written as an integer if the internal representation of the real is made
of all zeroes after the dot; e.g.:
10 PRINT 1.0
will print
1
Notice the space before the number; a place for the sign is always printed
in Dartmouth BASIC and, if positive, a space - not a plus - is printed.
Sometimes reals behave like integers if they have too many zeroes after the dot
and before a non-zero digit; e.g.:
10 PRINT 1.000000002
will print
1.
Notice the dot after the number, meaning that the number is not really an
integer, but a "masked" real.
Any number may be input using the ten digits, the prepended minus, the dot and
the letter E for powers of ten (.2 is accepted, 1E2 too, E2 is not). Follow
instructions on the 1964 manual, dib is built on the same basics.
Number limits are set as follows:
- the max (positive) real is 1E75, identified (in the source) as INFF
- the min (negative) real is -1E75, identified as MINFF
- the smallest absolute value of a real is 1E-75, identified as ZERO
These values have been set after reading on [9], page 5, point 8, that "The
maximum exponent allowable in the GE-235 is 75".
There are some issues, here; the INFF/MINFF/ZERO limits are not set into
values themselves, but only in printing; so the internal value is preserved
for further calculations; this causes dib to be... ah... clever than the
original (see ahead, errors 30/31).
According to [11], the use of booleans was not in the Original Dartmouth BASIC;
dib, on the contrary, treats any expression as a truth value, since truth
values are simply real numbers (set as TRUE=-1 and FALSE=0); of course, this is
meaningful only if you print out a truth value, e.g. PRINT 3>2 (which is quite
useless) or if you use a variable as truth value, e.g. IF A THEN (which was,
probably, not available in the original BASIC); in the first case the output
will be -1, in the second case, the part after THEN will be executed if A is
different than 0 (any value). Remember that this may not be available in other
dialects.
Variables
---------
dib has the standard variable names as the original BASIC, nothing more. So
A..Z and A0..Z9 are the ranges of all the available variable names. Double
letters or even longer names are forbidden - e.g. AB or TANKVOLUME (but see
next subparagraph called "Capitals").
There are no string variables.
Arrays
------
dib uses arrays in the same way of the original basic, with a DIM statement
to instantiate some memory space for the array; any undeclared array is
automatically instantiated to a 10 or 10x10 array (the dimension depends on
the array you invoke, that is A(2) will instantiate a vector, while A(2,4) will
instantiate a matrix). Of course, any reference to an uninstantiated array
with indexes greater than 10 will raise an error.
Note: the automatic instantiation is not taken into account with the MAT
commands; when using a MAT command, you have to instantiate the arrays before
(this is the same behavior, of course, of the original BASIC).
Arrays declared with DIM Z(N) or DIM Z(N,B), where B is 0 or 1 according to
OPTION BASE (0 or 1), behave in the same way with all commands. In effect the
former are pure vertical arrays, the latter are degenerated matrices,
constituted by a column only. (This kind of vectors are those used for solving
equations systems of the kind AX = B, where A is a square matrix, B is the
vector of known terms, and X is the solution vector, both vertical and as
high as the matrix height (the system is solved premultiplicating both sides
by the inverted matrix A-1: (A-1)AX = (A-1)B to get X = (A-1)B; the solutions
vector is simply obtained multiplicating the inverse by the knowns vector in
this order: matrix A must be square, size NxN, and B must be a vertical vector
of size N.) The only difference between the two is that DIM Z(N) defines an
object of type "vector", while DIM Z(N,B) defines an object of type "matrix",
but this is of little or no importance for the programmer.
An array declared with DIM Z(B,N) where B is 0 or 1 according to OPTION BASE
(0 or 1), is a horizontal array, in effect a degenerated matrix constituted by
a row only, which is an object of type "matrix". It can be transposed to a
vertical one ("vector" or "matrix") and back, as well as a unidimensional
vector (vertical) may be transposed to a horizontal vector.
Remember that with option base set to 1 (or using the -b option at start), you
cannot dimension vectors with indexes starting from 0!
A final note: with OPTION BASE set to 0, you may be tempted to dimension
peculiar arrays like DIM A(0) or DIM A(0,0); your intention would probably be
that of having a degenerated one-element array. Well, this won't work in dib,
depending on the particular internal rapresentation of arrays: such an array
would be interpreted as an uninstatiated array, and redimensioned to a 10 or
10x10 array the first time A(0) or A(0,0) is invoked; any reference to A(0)
or A(0,0) will of course be preserved, but beware when you use MAT PRINT on
such arrays!
Arrays can be redimensioned, even using different cases, like DIM A(6) and
DIM A(4,4) in the same program. I don't know if this feature is common in other
BASIC interpreters or compilers. In any case, the DTSS emulator by T. Kurtz
admits this feature, and so does dib.
Arrays cannot contain strings.
Precedence
----------
Precedence among all the operators (not all available in default mode - see
ahead), is set according to the following schema (higher to lower)
level 7: ()
level 6: NOT
level 5: ^
level 4: * / \ MOD
level 3: + -
level 2: < > = <= >= <>
level 1: AND OR XOR
level 0: EQV IMP
The Original BASIC version II had a bug, causing an expression like -3^2 to
yield 9 (as if ^ had a lower precedence than unary minus); version III did
correct it, and -3^2 yielded correctly -9). dib, accordingly to version III,
yields -9, because ^ has a higher precedence than unary minus.
Screen
------
A program line is 75 characters wide and so is screen output; anything beyond
the 75th character in program lines will be lost; should they fall beyond the
screen limit during output, numbers will be printed on a new line, strings will
be cut.
Screen columns are numbered 0 to 74, and this is quite different from the
underlying screen, which, in any real terminal or terminal emulation is at
least 80-characters wide.
This reflects the original input space of the Dartmouth BASIC, so you should
never use program lines longer that 75 **in all** (line numbers included). Use
an editor with characters count like vim.
I took any care to simulate the output **exactly** as in the original BASIC.
Some differences arise with calculation results, because modern CPUs behave
better than ancient ones...
Program lines formatting
------------------------
A program line is a text line with the first character(s) being digits, and
followed by a single statement with its arguments.
You can put any blank space into the line, even in the middle of a statement:
10 PRINT "HELLO, WORLD!"
10 PRINT "HELLO, WORLD!"
10PR INT"HELLO, WORLD!"
10 P R I N T "HELLO, WORLD!"
Previous lines are all equivalent, since all spaces/tabs are discarded during
the line processing (of course, not for spaces/tabs into strings!).
This said, you can format your listing to make it more readable, like:
10 FOR I=1 TO 10
20 PRINT I
30 FOR J=1 to I
40 PRINT "-->";I*J;
50 NEXT J
60 NEXT I
70 END
without any risk of misinterpretation. If you want to use an editor with
syntax coloring for BASIC, or use vim with the syntax file dib.vim, though
- see par. 3.8 - take care to write all statements with consecutive letters,
in order to achieve the colored syntax. PRINT will be colored, PR INT will not
(but will work).
Moreover, if you want to run your listings under different BASICs, be careful:
they may not recognize broken statements.
I don't know if the original Dartmouth BASIC could accept broken statements
like PR INT instead of PRINT; dib does, anyway.
Program lines may also be:
- void lines (or lines composed by spaces, tabs and blanks, which are simply
discarded); they are equivalent to lines with a line number only, which
delete (if present) the stored line with that very line number; in fact,
in case of two (or more) lines with the same line number, only the latter is
maintained; you can use this trick to do some debugging; simply rewrite at
the bottom of the file the lines to be substituted without deleting them
really. Use a line number alone to temporarily disable a line.
- lines beginning with '#'; they are discarded too, to enable some BASIC
scripting; simply copy the following line as the first line in the BASIC
source file (this is not an original Dartmouth BASIC feature, of course),
whose name, for this example, is :
#!/bin/sh dib
Put all the options you want. Then type from console:
$ chmod +x
and from now on you will have a sort of executable in BASIC.
Lines may also be scattered in an unordered way: the reordering is done
automatically during loading.
Capitals
--------
All statements must be written in capitals; PRINT and print are not the same,
the second raising an error, but dib, differently than the original BASIC,
will gently accept lower letters into strings. The following will behave as
expected:
10 PRINT "UPPER LETTERS"
20 PRINT "lower letters"
There is even a further note, here. I don't do any check about lower or
upper letters for variables, and the variables memory space of dib is enough
for all. So A and a are two distinct variables, A(1,1) and a(1,1) are two
distinct arrays elements, FNA and FNa are two distinct functions!
Take this note with care, I) because this behavior differs from the original
BASIC; II) because it may make your listing incompatible for other BASIC
interpreters and compilers; this said, you can count on twice the variables
number of the original BASIC, twice the number of arrays, twice the number
of functions... just in case you need it!
Preparsing
----------
As said, dib is an interpreter, not a compiler. Nonetheless, some commands are
preparsed before execution:
- END statements are checked in default mode for the following conditions:
there must be only one END and it must be the last statement in the code;
if it's not so, an error will be raised and the program won't be executed.
In extended mode, no check is done for END, neither for being unique nor for
being the last.
- DATA statements are parsed to gather all the data information. Data are
sequentially stored into a vector, and READ proceeds reading it from start.
RESTORE resets vector pointer to the first element. Thus, during execution,
DATA is a statement without effect, and is simply discarded.
- DEF FN structures are parsed to gather all functions and all the variables
that are used as arguments. Successive calls to the DEF FN function force
a parsing of the function expression after instancing process variables.
Thus, duting execution, DEF is a statement without effect, and is simply
discarede.
All the errors that have some reference with END, DATA or DEF occur even before
the first program line is seen by dib.
Remarks
-------
The syntax that must be observed, apart from inner spaces, is simple, as in
the 1964 manual, and may be condensed into this terse sentence:
one statement per line
The colon to divide multiple instructions on one line is NOT permitted, and
this reflects exactly the Dartmouth BASIC original philosophy (this is true
for default mode, while extended features permit a limited use of multiple
instructions for assignments).
Errors in statements, in writing numbers, in functions, in relations and many
other syntax errors are exposed ahead.
Finally, I like the motto at page 21 of the 1964 manual, here reported:
TYPING IS NO SUBSTITUTE FOR THINKING
Many programmers (I'm the first) should learn from this.
2.4 DEFAULT FEATURES
----------------
Here you will find the list of all dib's default statements and features:
Available statements and specs
-----------------------------
- PRINT
display strings enclosed into double quotes, or expression built up from
numbers, variables and operators; arguments may be followed by comma or
semicolon; PRINT accepts even the classic string/value without comma or
semicolon)
- FOR..TO..STEP/NEXT
execute cycles with a depth of 26 levels (the original basic admitted, for
version II, 26 FOR cycles in total); NEXT must be followed by the variable
name.
- IF..THEN
(followed by a valid address) executes jumps to a specific address if
condition after IF is true.
- GOTO
jumps to any legal address (jumping out of a FOR cycle with GOTO or IF/THEN
causes a cycle break); of course, GO TO is accepted.
- GOSUB/RETURN
(one level depth) jumps to a subroutine and get back.
- LET
(required) for single assignments.
- END
as the last statement, which is required.
- INPUT
enabled for multiple vars input, but unable to print input strings (e.g.
INPUT "Enter a number";N won't work).
- DATA/READ/RESTORE
(only for numbers), with a maximum of 300 values
- REM
for comments; of course, REMARK is accepted; the apostrophe as a comment
in the middle of the line is available
- DEFFN
to define a function with one argument (e.g. DEF FNX(A)=...).
- PAGE
to clear terminal and simulate a new printing page.
- STOP
which acts as END but may be repeated anywhere.
- DIM
with one or two dimensions arrays, with A..Z names (A0..Z9 names as array
identifiers are not available).
Notes:
- line numbers range is 1-99999
- operators are the classic fab-four (*/+-) plus powering (^)
- relational operators are the classic six (= <> <= >= < >)
- a strictly correct syntax is necessary for the parser to work; so (and this
is not bad at all) no freedom is left in leaving behind closing
parentheses; no doubt: this enhances clarity and eases corrections.
- the powering operator may be followed by unary operators - and + (e.g.
12^-1E-2 or 3.2^+4.2 or A^-E1 are allowed); in any case, for a better
reading, you may enclose exponent into parenthesis.
- DIM A(N) dimensions a unidimensional array, which is by default a vertical
array; this easies calculations of matrices by vectors; if you ever want
to dimension a N-elements horizontal array, do it through DIM A(0,N-1) with
base index set to 0 or DIM A(1,N) with base index set to 1; notice though
that DIM A(N) dimensions a vector, while DIM A(0,N) is not a vector but a
special case of a matrix. You can mix their use in any type of calculation,
anyway.
- variables list in INPUT may be separated by commas or semicolons, and even
mixed up (e.g. INPUT A,B,C or INPUT A;B,C).
Available functions and specs
-----------------------------
- ABS
- ATN
- COS
- EXP (exponential)
- INT (integer part)
- LOG (neperian base)
- RND (dummy parameter required between parentheses)
- SGN
- SIN
- SQR
- TAN
Available MAT statements and specs
----------------------------------
- MAT A=B+C, MAT A=B-C, MAT A=B*C (where the lvalue cannot occur after the
'=' sign, e.g. MAT A=B*A is not valid)
- MAT ZER
- MAT CON
- MAT TRN
- MAT INV
- MAT IDN
- MAT PRINT
- MAT INPUT (this statement belongs to version IV, to tell the truth)
- MAT READ
- MAT A=(k)*B (where the lvalue cannot occur after the '=' sign and k must be
enclosed into parenthesis; k may be any valid expression fitting the line).
Notes:
- A0..Z9 variables cannot be used into matrices
- all matrices and vectors must have been declared with DIM, even if
smaller in dimension than 10 in either side; this is the restriction n° 1
presented at page 51 of the October 1964 manual for the II edition: "A
matrix in a MAT instruction must have had a DIM declared", and I believe
this has not changed in the III edition of 1966. The restriction n° 2:
"While the same matrix may appear in a MAT statement and in an arithmetic
statement, it must occur for the first time in a MAT statement") is not
observed by dib.
- MAT A=B is not available. Use MAT A=(1)*B in its place.
- MAT A=-B is not available; in case you need such an operation, do it
as MAT A=(-1)*B.
- MAT READ, ZER, CON, IDN may redefine arrays (which, if greater in
dimension than 10 in either side, must have already been instantiated
with DIM), but only to reduce the array size in either side.
- MAT TRN transposes argument matrix, and must be used also with vectors;
- MAT INV sets a system var, named DET, which contains the determinant;
DET must not be called before a MAT INV, and if it contains zero after
an inversion, the matrix is singular.
DET value retains its value until next MAT INV statement (it will be
replaced by next determinant value) or end of program.
- MAT INPUT sets a system var, named NUM, which contains the number of
input values (which may differ from the vector/matrix global number of
elements); NUM may be called anytime, but it's meaningless if called
before a MAT INPUT (i.e. it's null). Besides, if you use the compact
form MAT INPUT A,B,C to input values for matrices A, B and C, at the
end of the input process, NUM will refer to the last matrix (C here).
So, if you input a bunch of numbers to fill A and partly B, NUM will
be set to 0, because C received no values. If you need to check NUM for
every matrix input, set a MAT INPUT for each matrix.
- As a means to understand how good the inversion of a matrix is,
multiply the original matrix by its inverse; the closer are diagonal
elements to 1 and the closer are all other elements to zero, the better
is the inversion; in particular, I observed that if elements that should
be zero are in the order of magnitude from 1E-3 to 1E-6, the inversion is
not much accurate, but in most cases satisfactory. If the order of
magnitude is smaller than 1E-7, the result is good. If order of magnitude
is even smaller than 1E-10, no better result can be achieved by dib.
- As a final remark, I observe with pride that my inversion algorithm can
solve what Valentin Albillo calls "Mean Matrices" (ill-conditioned and
unstable matrices that the HP-71B pocket computer cannot completely
resolve). See [8].
2.5 EXTENDED FEATURES
-----------------
By invoking dib with the -x option, a number of BASIC extensions are enabled;
these extensions want to emulate further versions of the Dartmouth BASIC, but
without any specific reference (in particular, strings are not enabled, in this
dib's version, while they were in version IV of the Dartmouth BASIC).
The extended features are summarized here:
Available statements extensions and specs
-----------------------------------------
- DIM
now allows the dimensioning of arrays with A0..Z9 names
- IF..GOTO
with the same behavior of IF/THEN (followed by an address)
- IF..THEN
may be followed by some assignment (with or without LET)
- IF..THEN GOTO
is admitted
- GOSUB/RETURN
with an increased level depth (80 by default)
- END
is not required
- LET
is not required (even after THEN), and multiple assignments may be done
- INPUT
may accept a string before the variable list, and followed by comma,
semicolon or directly by the list (e.g. INPUT "VALUES";A,B or
INPUT "VALUE",A,B or INPUT "VALUE"A,B)
- ON..GOTO/ON..THEN
equivalent
- OPTION BASE
followed by a number (0 sets zero as first index, any other value sets one
as first index)
- RANDOMIZE
- CHANGE..TO
which works only from strings to arrays; the string must be explicitly
enclosed into double quotes and not contained into a variable
- TAB()
to set next printing position; as said, columns are numbered from 0 to 74
(i.e. TAB(10) sets column 10, which is the 11th, as next printing
position). TAB is a specifier of PRINT, and cannot be used alone or into
a math expression.
- CHR$()
prints the ASCII character of the value calculated into the parenthesis;
CHR$ is a specifier o PRINT and cannot be used alone or into a math
expression.
Notes:
- line numbers range is now increased to 1-119880
- some math and logical operators have been added: MOD, \ (integer
division), AND, OR, XOR, EQV, IMP (they all behave as infix operators),
NOT (it's a unary logical operator that precedes the expression whose
truth value must be reversed. Its priority is higher than any other, so
NOT A*B is equivalent to (NOT A)*B ).
Other logical operators may be obtained in function of existing ones:
- NXOR is equivalent to EQV
- NAND is NOT AND; e.g.: A NAND B <=> NOT (A AND B)
- NOR is NOT OR; e.g.: A NOR B <=> NOT (A OR B)
Sometimes I see the XOR operator written as EOR in other BASICs, so this
name is enabled into dib's extended features, with the same exact meaning
of XOR.
- The assignments after IF..THEN in extended mode may be separated by
comma or colon, and even mixed; but only the colon may be compatible
with other compilers and interpreters; e.g.:
10 IF A = 1 THEN E = 14, T = 45
may be not interpreted correctly by others compilers or interpreters,
while
10 IF A = 1 THEN E = 14: T = 45
will be.
- INPUT may be followed by a string, which will be printed before asking
for variables input; after the string you can put a comma, as in
INPUT "ENTER NUMBERS",A,B
or a semicolon, as in
INPUT "ENTER NUMBERS";A,B
or nothing, as in
INPUT "ENTER NUMBERS"A,B
- The logic of CHR$() followed by comma or semicolon and by something else
is the same of the output processed by PRINT; if, however, CHR$() is
followed by another CHR$, or by comma/semicolon and nothing else, no
advancing in the printing position is done, so that CHR$() may be used
to build strings.
If used followed by nothing, a Carriage Return will be output each time.
Available functions extensions and specs
----------------------------------------
- ACS
- ACSH
- ASC
- ASN
- ASNH
- ATNH
- CNORM(A) yields the column norm of matrix A
- COSH
- COT
- DET(A) yields the determinant of argument square matrix A
- DOT(A,B) yields the dot product (scalar) between two unidimensional vectors
- FNORM(A) yields the Frobenius norm of matrix A (a.k.a. Euclidian norm)
- GAMMA
- PI returns the Greek pi value (3.14159...)
- RND now does not require an argument
- RNORM(A) yields the row norm of matrix A
- SINH
- TANH
Notes:
- ASC print the number equivalent to the ASCII character of the string
argument, enclosed or not into parenthesis, i.e. the following lines yield
the same value (65):
10 PRINT ASC("ABBA")
20 PRINT ASC(ABBA)
The double quotes themselves cannot be used, since dib doesn't recognize
any escape character. But if you remember that their ASCII value is 34,
you can use it "as is", and print double quotes with CHR$(34).
- FNORM yields the Frobenius norm, which is the square root of the sum of
the squares of all the elements of the argument matrix
- RNORM is the row norm, which is the largest sum of the absolute values
of the elements in each row of the argument matrix
- CNORM is the column norm, which is the largest sum of the absolute values
of the elements in each column of the argument matrix
- for FNORM, RNORM and CNORM, argument matrix is not required to be square,
and also the norm of unidimensional vectors will be calculated.
- DET(A) and DET are two different entities; in effect, DET(A) is a
function, while DET is a variable. DET holds the determinant after
a MAT INV(A) or a DET(A) is performed, and may be used anywhere until a
new MAT INV(A) or DET(A) is done. DET(A) recalculates the determinant of
the argument matrix regardless of the existence of DET, and with no
check about the fact an inversion has been done. In any case, after
DET(A), DET is available, because dib performs an implicit inversion to
test for determinant existence while calculating it.
- DOT(A,B) takes two vectors (a.k.a. lists) as arguments; these vectors
may be unidimensional vectors dimensioned with DIM A(N), or
unidimensional vectors dimensioned with DIM A(N,B) or DIM (B,N), where
B is the OPTION BASE, 0 or 1; the latter may be considered vectors here,
for the purpose of the DOT product, but in effect they are degenerated
matrices, built up by, respectively one row or one column only.
Available MAT extensions and specs
----------------------------------
Notes:
- MAT A=B is available
- variables A0..Z9 may be used as matrix names
- MAT A may simultaneously occur to the left and to the right of the '='
sign in additions, subtractions, multiplications and scalar
multiplications, e.g.: MAT A=B+A, MAT A=A-B, MAT A=B*A, MAT A=(k)*A, or
even MAT A=A+A.
If you want to always use dib's extended features, simply set ef=1 in the file
dib.h and recompile; from now on, the -x option will "turn off" extended
features, rather than enabling them.
2.6 ERROR MESSAGES
--------------
dib is, at present, an interpreter, not a compiler. Error treatment thus cannot be the same of a compiler.
Basing on this simple fact, I had to reconsider the whole error treatment,
since, while a compiler does multiple passes to compile, being one of the
first the syntax check, and so being able to print a long listing of error
messages, an interpreter should stop after the first error, because going on
would mean either instantiating not allocated variables, or calling not
existing addresses, or doing useless loops, or something equally bad.
I came up to the following decisions:
- set up a general error treatment system to stop at the first met error, but
capable of reverting to a multiple error generator changing a flag only (use
it at your risk!);
- use the same error strings of the original compiler, as exposed on [1];
- use an extended set of strings, partly derived from [5], and partly conceived
by me, where the original compiler lacked proper messages, or to expand error
information to some extent
These decisions forced me to recalibrate errors, discerning which one could
safely let the program flow and which one had to be considered definitely a
stopper. In the following paragraphs, errors recognized by dib and their own
stop-code are reported (yes/no means that things are different with extended
features enabled).
If invoked with option -c, dib won't stop after meeting many errors (not all!),
and will continue until a definitely bad thing has happened, writing in the
meantime all the detected error messages. Errors which are considered
dangerous for the computer memory, or which prevent dib from going on, will
immediately stop the interpretation.
If invoked with option -l dib will print on standard output the complete list
of error codes and their messages.
2.6.1 STANDARD ERROR MESSAGES
-----------------------
Standard messages are exactly the same of the original 1964 Dartmouth BASIC,
printed both in default and in extended mode.
In the following, "stopper" is an error big enough to prevent dib from going on.
0. DIMENSION TOO LARGE [NOT USED]
(stopper: no)
It occurred in Dartmouth BASIC when the size of an array was too large for
the available storage. In practice, this cannot be replicated in dib, because
the available memory is predetermined in dib.h, and can be expanded at need
(and of course, depending on your system memory).
1. ILLEGAL CONSTANT
(stopper: no)
It occurs when there's an incorrect form in a number:
- more than 9 digits;
- other than [+-.0123456789E] in a number.
The first condition cannot be observed by dib, which makes use of the
strtod() C function, which has higher capabilities than Dartmouth BASIC's
original parser. In practice, you'll rarely meet this error, because strtod()
is very very clever.
2. ILLEGAL FORMULA
(stopper: no)
It occurs in case of:
- missing (closing) parentheses;
- illegal variable names;
- missing multiplication operators (implicit multiplication is forbidden);
- illegal numbers (in the original Dartmouth System it might not refer to
the preceding error 1; probably it occurred during execution in case of
overflow; if it's so, I cannot replicate it, due to the way gcc treats
overflow).
3. ILLEGAL RELATION [NOT USED]
(stopper: no)
It occurs when there's not a valid relational expression between IF and THEN;
There are some problems in catching this error for dib, because the parser
always interpret as wrong numbers what it cannot understand. For example, the
following code fragment:
10 PRINT 3<<4
20 IF A=>6 THEN 10
causes dib to emit the ILLEGAL CONSTANT error message at lines 10 and 20,
because it interprets the first as 3 < (<4), and <4 is an illegal constant,
and the second as A = (>6), and >6 is another illegal constant.
So this error message is never issued.
4. ILLEGAL LINE NUMBER
(stopper: yes)
It occurs when:
- the line number is not available or obtainable
- the line number is greater than 99999
The second is detected as a superimposed limitation, because the effective
memory size may be increased at pleasure for both (to a certain extent); in
any case, the limitation is not considered if the extended features are
enabled, but the effective increment is low: the limit is set to 109890
(=110x999), of which only the first 99999 are available in standard mode.
5. ILLEGAL INSTRUCTION
(stopper: no)
It occurs when there's some illegal instruction (not a valid BASIC statement)
after the line number or in a formula or in an expression.
If you're familiar with Commodore BASIC, you'll remember the ubiquitous
?SYNTAX ERROR; it's the exact correspondent.
6. ILLEGAL VARIABLE
(stopper: no)
It occurs when an illegal variable is detected (for instance, a two-letters
variable name has been used, like AB).
7. INCORRECT FORMAT
(stopper: no)
It occurs when a wrong statement has been written in FOR..NEXT..STEP or
IF..THEN structures.
8. END IS NOT LAST
(stopper: yes/no)
It occurs when:
- END is not in the last line;
- there's more than one END statement.
Both errors are not highlighted if the extended features are enabled.
9. NO END INSTRUCTION
(stopper: yes/no)
Self explanatory. Not highlighted if the extended features are enabled.
10. NO DATA
(stopper: no)
It occurs when:
- there's a READ without DATA.
- a RESTORE is called without DATA statements.
It's perfectly legal having a DATA with no READ/RESTORE.
11. UNDEFINED FUNCTION
(stopper: no)
It occurs when FNX is called without defining DEF FNX first.
A DEF FNX definition may appear anywhere (it's caught before execution),
but it *must* appear somewhere, in order for FNX to find what to calculate.
12. UNDEFINED NUMBER
(stopper: yes)
It occurs when GOSUB, GOTO or THEN are given a non existent destination
line number.
13. PROGRAM TOO LONG [NOT USED]
(stopper: no)
In Dartmouth BASIC, at least first versions, there was a limited number of
program lines which were available. When a program reached that length, this
error message appeared, maybe in conjunction with error 19 (see ahead).
dib uses a huge list of pointers to string lines, whose index is the
correspondent line number, so this error is meaningless and never issued.
14. TOO MUCH DATA
(stopper: yes)
It occurs when there are more values for DATA than those available (this
limit is 300 for standard mode, and 999 for extended mode.
15. TOO MANY LABELS [NOT USED]
(stopper: no)
It occurred in Dartmouth BASIC when there were too many strings in the
program (due to memory limitations).
I cannot use it, I don't want to use it!
16. TOO MANY LOOPS
(stopper: yes)
It occurs when there are too nested FOR..NEXT loops than those available
(this limit is set to 26). Of course, you can use even thousands of
FOR..NEXT loops, if they are not nested!
17. NOT MATCH WITH FOR
(stopper: no)
It occurs when:
- there's a NEXT with a different variable than that used within FOR
- there's a wrong NEXT nesting (e.g. FOR A, FOR B, NEXT A, NEXT B)
18. FOR WITHOUT NEXT
(stopper: no)
The program ends and no NEXT has been found.
19. CUT PROGRAMS OR DIMS [NOT USED]
(stopper: no)
This error (which looks rather a warning) has some meaning only with tiny
resources. Used in Dartmouth BASIC and not in dib.
20. SUBSCRIPT ERROR
(stopper: yes)
A non existent array index has been called. It may even refer to differences
in a DIM declaration or peculiar usages with MAT statements.
21. ILLEGAL RETURN
(stopper: no)
It occurs when a RETURN not related to any GOSUB is found.
2.6.2 EXTENDED ERROR WARNINGS
-----------------------
The following warnings are meant to report odd situations, and don't stop the
program flow; they don't appear in the original 1964 BASIC manual, but I
reputed them meaningful in a programming environment. Most of them are
retrieved from the compiler assembler source, some from the DTSS simulator
by T. Kurtz, and some have been invented by me. None of them is a stopper.
Numbers not addressed are unused, at present.
22. OUT OF DATA
It occurs when READ cannot read DATA values anymore. This is different from
the NO DATA error message: the latter means that no data has been found
(this may mean no DATA statement at all), while the former means that all
data have been read and there's nothing left.
As stated at page 7 of the 1964 manual, this causes the program to stop, with
no peculiar message. So I enable this (non-stopper) warning only in extended
mode.
23. SQUARE ROOT OF NEGATIVE NUMBER
24. LOG OF NEGATIVE NUMBER
25. LOG OF ZERO
26. ABSOLUTE VALUE RAISED TO POWER
27. DIVISION BY ZERO
These warnings are shown when you execute an illegal math operation; things
are 'adjusted' and the program flow is not interrupted.
When I say 'adjusted' I mean:
- absolute value of a negative number is taken before performing a
square root
- the logarithm of zero or a negative number returns the lower value MINFF
- a negative real cannot be raised to power, so its absolute value is taken
- a division by zero returns the dividend (that is, it's not executed)
This behavior reflects the original Dartmouth BASIC one.
30. OVERFLOW
31. UNDERFLOW
The first warning appears when a number greater than INFF (or lower than
MINFF) is met, either as itself or as a result of a math operation.
The second appears when the absolute value of a number is lower than ZERO
(but not zero), that is the lower limit of this emulator, either as itself
or as a result of a math operation.
I said "as a result of a math operation"; to this, I must add that I let
the CPU perform all the intermediate calculations, so it's occasionally
possible that these warnings don't get printed; for example, if you multiply
1E50*1E50*1E-50 in an expression, the first intermediate result is surely
an overflow for dib, but not for a modern CPU; then, when next operation
returns a value not overflowing dib's capacity, no warning is issued
while evaluating this final result.
32. ZERO TO A NEGATIVE POWER
33. ZERO TO THE ZERO POWER
The first warning appears when you try to calculate 0 to the power of a
negative number, and the result is set to INFF (which tends to simulate
1/(0^e) or (1/0)^e, with 'e' positive, both leading to infinite).
The second appears when both base and exponent are zero, and the result is
set to 1 (because the function x^x approaches 1 as x approaches 0 from the
right - see [10]).
34. GOSUBS NESTED TOO DEEPLY
This warning appears when you go past the GOSUB..RETURN limit for inner
subroutines; as default, you cannot perform a GOSUB into another GOSUB; from
the Oct. 1964 manual, page 43:
"The user must be very careful not to write a program in which a GOSUB
appears inside a subroutine which itself is entered via a GOSUB; it just
won't work."
In extended mode, this limit is increased to 80, but should you go past this
limit, the message appears the same. I guess, anyway, you'll NEVER go past 80
levels of GOSUBs!
35. ARRAY INDEX MUST BE GREATER THAN ZERO
This warning occurs in case you use index 0 in dimensioning arrays while
option base is set to 1; in this case dib prints this warning before exiting)
36. NO MATRIX INVERSION DONE YET
Self explanatory. The determinant calculated after this warning (e.g. before
a matrix inversion) is meaningless.
37. IGNORING ONE-ELEMENT LIST OR TABLE
If you dimension a one-element array (vector or matrix) with option base 0,
using DIM A(0) or DIM A(0,0), the interpreter won't see this as a matrix
dimensioning, and will set an implicit 10 elements or 10x10 elements array
the first time you use a reference to the element; this happens only with
option base 0 and you won't lose the object: only be conscious you have a
whole array, not just a one-element array.
You'll never see this warning with option base 1 if you try do dimension a
one-element array with DIM A(1) or DIM A(1,1).
38. ASIN OR ACOS ARGUMENT MUST BE BETWEEN 1 AND -1
39. ACSH ARGUMENT MUST BE GREATER THAN 1
40. COTANGENT OF ZERO
These messages catch the violation of the relative math functions domain,
without stopping program flow. In case of violation, the yielded result is
always zero except for error 40, which yields (of course) INFF.
These messages appear only in extended mode, since hyperbolic functions
are available only in extended mode.
41. INVERSION OF A SINGULAR MATRIX IS NOT POSSIBLE
This warning appears when either the Gauss factorization is not possible,
because the matrix is singular, or the determinant is null, again because the
matrix is singular. In either case, the determinant is null and the message
warns the programmer in order to get rid of the result matrix values.
2.6.3 SYSTEM MESSAGES
---------------
Sometimes, things go in such way dib cannot manage them. In such cases, errors
are printed in lower letters, preceded by the identifier "dib:", and the
program inevitably stops. Here's a list of all the system errors:
dib: out of memory for arrays.
dib: out of memory for DEF.
dib: file not found.
dib: unable to close file.n
dib: line <> is beyond domain.
dib: out of memory for line <>.
dib: -<> is an illegal option.
dib: missing file name.
dib: out of memory for ultimate END.
These error messages are auto-explicative; the <> matches with a value which
is calculated or retrieved during execution, and incorporated into the message.
You're likely to never see last system error message.
2.7 THE EXAMPLES
------------
In the package there are four directories of examples:
- the directory named 1964/ gathers all the examples featured in the 1964
manual for version II of the Dartmouth BASIC. They are named according to the
page number in which they appear. The output of those programs has served as
target for refining the dib's PRINT statement. They must be run safely with
no options.
- the directory named OWN/ gathers all the specific examples I created for dib;
the subdirectory EXTEND/ contains examples which must be executed with the
extended features enabled;
- the directory MATRIX/ contains various examples of matrix calculations; the
subdirectory EXTEND/ contains examples which must be executed with the
extended features enabled.
- the directory GOTTFR/ gathers all the example of the 1st edition of [3]
which could be applied to dib with the -b option, to set option base to 1
(the Pittsburgh machine on which these examples ran used a consistent index
for arrays starting from 1); the subdirectory EXTEND/ contains examples which
must be executed with the extended features enabled.
2.8 THE vim 'dib' SYNTAX FILE
-------------------------
In the package you will find the 'dib.vim' file. If you don't use vim, well,
skip this paragraph and forget the file.
If you use vim as your current editor, here's some instructions for installing
the dib file (only for UNIX users).
2.8.1 INSTALLING dib.vim
------------------
Locate the .vim directory under your $HOME. Add the two lines
" dib (Dartmouth BASIC)
au BufNewFile,BufRead *.dib setf dib
to filetype.vim (and create it if it doesn't exist); now step into .vim/syntax
and copy here the file dib.vim. Done.
2.8.2 MAPPING THE DIB SYNTAX
----------------------
Of course, you may want to use vim on files created with deer, so the extension
is not present. In this case, I map the dib syntax within the vim/gvim resource
file (for me $HOME/.gvimrc), adding the following line:
:map :set syn=dib
Of course you can map any key you want. From now on, load the file and hit F2:
the colored syntax will activate.
3. CONCLUSIONS
-----------
In the end, there are some people I want to thank, because their work made my
job easier (or even possible).
The first one is Diomidis Spinellis, the author of dds_basic, the program which
gave me the idea and offered me a frame on which basing my code.
I learned a lot from his programming style, which is fine, essential, smart.
The second one is professor Tao Pang, from UNLV (University of Nevada, Las
Vegas), for the book "An Introduction to Computational Physics - 2nd edition",
Cambridge ed., 2006, a very useful manual for implementing a lot of scientific
and mathematical routines and functions. I thank him again because he made
available most of its software through the Internet, and indeed the first
implementation of matinvert() was based on his elgs() and migs() functions,
before making up my mind and implementing my own.
The third one is Jack W. Crenshaw, the author of "Math Toolkit for real-time
programming", CPM Books, 2000, an invaluable mine of math tools, humor, style;
he's a man with a vivid intelligence, capable of getting into the harder
algorithm and turn it into a clear and easy tool. Every programmer should read
this book. And figure out: I bought it by chance!
Last one is my wife Anna, who supported my absence while I was hidden in my
room trying to produce some working code; she complained, from time to time,
but she loves me enough to stand it...
*** ***
I cannot leave without remembering with love professor Kemeny (in memory) and
professor Kurtz, who created the BASIC programming language many years ago, an
easy and lightweight language, suitable for math and financial subjects, which
guaranteed me an entry point in computer science. Thanks and thanks again.
*** ***
Finally, I propose this new acronym for BASIC:
Broad Analysis with Simple and Intuitive Coding
I hope you like dib.
It's GPL: Enjoy!
4. BIBLIOGRAPHY
------------
The following documents and references played an important role during the
design and the coding of dib:
[1] "Dartmouth BASIC manual" for version II, October 1964, available as a pdf
file at
http://www.bitsavers.org/pdf/dartmouth/BASIC_Oct64.pdf
[2] "BASIC Sessions", by Thomas E. Kurtz, chapter XI of the book "History of
programming languages", about the original BASIC environment, 1977 ca,
available as a pdf file of a typewriter transcript (titled "BASIC") at
http://delivery.acm.org/10.1145/810000/808376/p103-kurtz.pdf?key1=808376&key2=4039224611&coll=&dl=ACM&CFID=15151515&CFTOKEN=6184618
A pdf file of the chapter XI of the issued volume (which contains the same
text) may be obtained through a free subscription at the acm.org portal.
[3] "Programming with BASIC", by Byron S. Gottfried, edition 1, 1975 (Italian
version, as "Programmare in BASIC", Schaum 1982).
[4] "Commodore 64 C= - Reference Guide for the Programmer, 1983 (Italian
version, as "Guida di riferimento per il programmatore"), Commodore
edition.
[5] Listing of the source code for version II of the Dartmouth BASIC compiler
available as a pdf file at
http://www.dtss.org/scans/BASIC/BASIC%20Compiler.pdf
[6] News about John Kemeny may be found at
http://cis-alumni.org/JKemeney.html
[7] News about Thomas Kurtz may be found at
http://cis-alumni.org/TKurtz.html
[8] "Mean Matrices", an article by Valentin Albillo on ill-conditioned
matrices is available as a pdf file at
http://membres.lycos.fr/albillo/calc/pdf/DatafileVA014.pdf
[9] "To Potential ALGOL Users", Sept. 29, 1964, a note to Dartmouth ALGOL
users by Stephen J, Garland, revised by D. W. Scott March 3, 1965,
available as a pdf file at
http://bitsavers.vt100.net/pdf/dartmouth/ALGOL_Sep64.pdf
[10] Su, Francis E., et al. "Zero to the Zero Power." Mudd Math Fun Facts.
http://www.math.hmc.edu/funfacts/ffiles/10005.3-5.shtml
where you can find an explanation to the fact that zero to the zero power
is 1. Check also
http://mathforum.org/dr.math/faq/faq.0.to.0.power.html
where it's stated:
"Consensus has recently been built around setting the value of 0^0 = 1".
[11] The BASIC entry in
http://www.math.bas.bg/~bantchev/place/basic.html
states that the Original BASIC didn't treat boolean values, so that
it's conceivable that a phrase like "IF A THEN" would issue an error
in Dartmouth BASIC.
*** ***
(written with gvim)
               (
geocities.com/it/tonibin/deer)                   (
geocities.com/it/tonibin)                   (
geocities.com/it)