This directory contains the sources and make files for an
Atari BASIC compatible basic dialect.

This is based on Atari Basic, as developed by Paul Laughton and Kathleen O'Brien,
Shepardson Microsystems, as found in: The Atari BASIC SOURCE BOOK by
Bill Wilkinson, Compute! Publications (1983)

Basic++ fixes a couple of known Atari Basic bugs and includes a couple of improvmenents
without impacting compatibility with existing basic code. It does not attempt to
extend the Atari Basic dialect beyond its current syntax. If you are interested in a
more powerful Atari Basic, get TurboBasic, Basic XL or Basic XE. Basic++ is a
"best efford" to squeeze as many useful Basic features into the 8K cartridge ROM space
as possible.

Basic++ sources are based on Rev.A Atari Basic, as published in the Compute! book
cited above, with many improvements and refinements. Source code was completely reviewed
and refined, and was made more concise to the original leaving headroom for some new
features.

At this time, the following Atari Basic bugs have been fixed:

- The parser allowed INPUT without any parameters. Now it needs to take at least one
  variable.
- A Ctrl-U as last component of a string argument to PRINT worked as if the PRINT
  statement included a semicolon.
- It was possible to DIM two-dimensional arrays overrunning the available memory
  because any type of overflow check was missing.
- A downwards block move of an exact multiple of 256 bytes moved the wrong memory.
- Basic Rev. A crashed on cascaded versions of multiple unary operators, in particular
  PRINT NOT NOT A or PRINT ++2 or PRINT --X crashed. Atari "resolved" this issue in
  Rev.B by not parsing such expressions, Basic++ allows then and implements them
  correctly.
- LOCATE apparently did not restore the input buffer pointer correctly and could have
  caused errors if followed by a VAL() that required the pointer to be seated
  correctly. Basic++ fixes VAL.
- NOTE and STATUS were also parsed correctly if their arguments were arrays.
  However, none of them worked with arrays correclty, so the parser was adapted
  accordingly to accept only simple numeric variables.
- POINT did not accept arbitrary expressions, though it could. Fixed that.
- CHR$(a)=CHR$(b) was always true, regardless of a and b, the same bug holds true
  for STR$(a)=STR$(b). Fixed both bugs.
- GRAPHICS closes the stream before testing whether its argument is valid, and hence
  could leave the screen unavailable for graphics operations.
- If the line READ reads from is deleted, the next READ started from the same offset
  of the following DATA line, and not from the beginning of the next DATA line. This
  got fixed.
- CONT continued two lines after the STOP line in case the line containing the STOP
  was removed.
- SOUND no longer overwrites Pokey SkCtrl, but rather uses the shadow register at
  SkCtrlShadw (0x232) to reset only the bits it needs for a proper sound output.
- The parser treated the ESC-character as a line-feed character and hence as a
  separator between commands. This got fixed and creates a parsing error now.
- Operator-typed keywords could be used as variable names, though not consistently.
  This was mostly due to a bug in the parser. Thus, one could write "PRINT GOSUB"
  but not "GOSUB=1", but "THEN=1" and "PRINT THEN". Depending on the parser
  context, some reserved token names worked, others not. The test for conflicts
  of string variables and operators was also incorrect. Now you can declare
  variables like ABS$ (no conflict possible), but an array named ABS() is forbidden.
  Similarly, an ordinary variable of the name ABS is not possible either, and
  neither THEN or GOSUB are valid as variable names, but THEN0 or GOSUB$ are
  non ambigious and hence valid.
- An error that is caused in the direct mode can no longer TRAP and hence cause
  confusion. Causing an error executing a command directly through ENTER will,
  however, cause a trap.
- If memory allocation failed when parsing a new variable, the variable name could be
  allocated without having allocated the memory for storing the variable value. If then
  a value is assigned to the variable, parts of the program memory were overwritten.
  Now the order is reversed, which means that in worst case 8 bytes of memory are lost,
  though the program remains functional.
- GOSUB or ON x GOSUB left the source line on the run time stack in case either the
  evaluation of the GOSUB argument failed, or the target line was not found. Hence,
  if the TRAP handler invoked return, it returned the origin of the faulty GOSUB
  and not to he caller of the function including the GOSUB.
- The ENTER command could not be aborted with BREAK.
- The DSPFLG (DirectFlag under Os++) which prohibits the execution of control characters
  is no longer implicitly reset by the error handler and by I/O errors. It is now
  reset whenever a new line is requested from the user (or by ENTER).
- An END or falling off the end of the program no longer allows usage of CONT
  to continue behind the end of the program.
- LIST now first checks whether it can open the output filespec before it
  attempts to store the program position onto the run-time stack. This avoids
  at least one race condition where a failed LIST resumes program execution with
  RETURN.

The following improvements have been made:

- The SQR function in Atari Basic was unbearably slow and unprecise as it uses the
  ancient Heron method. Numerical inaccuracies of the math pack division pile up and
  resulted in loss of accuracy. The new code uses a "digit by digit" algorithm that
  is not only faster, but precise up to the last digit ("one ulp" precision).
- The power function ("^" operator) was implemented in a very naive way and resulted
  in precision loss. Atari "fixed" that in Rev.B by rounding results, Basic++ uses a
  "divide and conquer" method by first computing the integer part and splitting off
  the fractional part when necessary. This improves precision and stability and
  ensures correct results for integer arguments.
- Atari Basic stored line numbers and offsets as return address for FOR-NEXT loops and
  GOSUB expressions and hence required a complete line-search to return to the
  previous statement. Similar to TurboBasic, Basic++ stores in addition an absolute
  address and continues from this address directly bypassing the search if it can
  ensure that the source code has not been modified in between.
- Atari Basic used a very ugly and hacky method of temporarily fiddling an EOL into
  strings used as file specifications when interfacing to CIO. Basic++ avoids touching
  the user program or code and copies the string before modifying it.
- Basic++ allows an empty second argument to LIST to list up to the end of the source,
  i.e. "LIST 100," lists all lines from line 100 on.
- Basic++ handles denormalized floating point numbers now correclty, especially when
  comparing numbers and testing numbers for zero.
- Basic++ "string variable splicing" now also allows empty splices. In particular,
  if "A$="HELLO"", then A$(6) is valid and returns the empty string. Similarly,
  A$(4,3) is the empty string. This avoids some pointless boundary checks when splicing
  strings.
- If RESET was pressed in the middle of a line or variable insertion, Atari Basic might
  have left an unusable program that crashed the system on a LIST. Basic++ will detect
  such cases and will clean up its program areas in such a case.
- The line seach for GOTO and GOSUB has been improved by avoiding a full search in case
  the target line is known to lie below the current line. It is then sufficient to search
  from the current line instead.
- ON x GOSUB had a bug that always pushed the current program position on the stack,
  even if x was not in range of the available GOSUB targets. The next RETURN would
  then return to the ON x GOSUB line, even though the GOSUB was never executed.
- If two CHR$s or two STR$s where part of the same expression, the second call would
  overwrite the result of the first. Hence, CHR$(A)=CHR$(B) would always evaluate
  to 1, regardless of whether A or B were equal. Similarly, STR$(A)=STR$(B) would
  evaluate to 1 if the number of digits in A and B are equal, regardless of their
  value.
- The parser allowed STATUS and NOTE to accept an array as argument, though the statements
  never worked correctly with array elements as arguments. Basic++ handles arrays for
  STATUS and NOTE correctly, and also allows them for LOCATE, INPUT and READ.
- For some strange reason, the parser did not allow arbitrary expressions for the arguments
  of POINT, though the statement supported them.
- The output of some transcendental functions have been improved. ATN returns now -90 or
  90 precisely for very large or very small arguments, and CLOG and LOG return 0 precisely
  for the argument 1.
- Access of one-dimensional array elements avoids now a multiplication and hence should
  be faster.
- Basic++ supports an AUTORUN.BAS file. If one is found when coldstarting the system, it
  is loaded and run.
- A binary file (basic.exe) for testing is now also generated by the build-process. The
  file includes the same basic plus a relocator that places it in memory where it finds
  room.
- Added a DIR command that is compatible to TurboBasic's DIR, both in its function and
  its token value.
