| ← Previous revision |
Revision as of 22:45, 3 September 2009 |
| Line 46: |
Line 46: |
| |
When not running a program, Atari BASIC was in ''immediate mode'', where lines could be entered (with a line number) to add a line in the program or modify an existing one, or commands could be entered (without a line number) that were executed immediately. Unlike most other BASICs, however, Atari BASIC allowed ''all'' commands to be executed in both modes. For instance most BASICs would only allow <code>LIST</code> to be used in immediate mode, while Atari BASIC would also allow it to be used inside a program. This was sometimes used as part of a way to produce [[self modifying code]]. |
|
When not running a program, Atari BASIC was in ''immediate mode'', where lines could be entered (with a line number) to add a line in the program or modify an existing one, or commands could be entered (without a line number) that were executed immediately. Unlike most other BASICs, however, Atari BASIC allowed ''all'' commands to be executed in both modes. For instance most BASICs would only allow <code>LIST</code> to be used in immediate mode, while Atari BASIC would also allow it to be used inside a program. This was sometimes used as part of a way to produce [[self modifying code]]. |
| |
|
|
|
| - |
Program lines could be up to three screen lines of 40 characters, so 120 characters total. The cursor could be moved freely in these lines, unlike in other BASICs where to get "up" a line one had to continuously scroll leftwards until the cursor wrapped at the left margin (and similarly to go down when wrapping at the right margin) — though that worked too. The OS handled tracking whether a physical line flowed to the next on the same logical line; the three-line limit is fairly arbitrary but keeps lines below 128 characters and so probably reduces the chances of buffer overflow.
|
+ |
Program lines could be up to three screen lines of 40 characters, so 120 characters total. The cursor could be moved freely in these lines, unlike in other BASICs where to get "up" a line one had to continuously scroll leftwards until the cursor wrapped at the left margin (and similarly to go down when wrapping at the right margin) – though that worked too. The OS handled tracking whether a physical line flowed to the next on the same logical line; the three-line limit is fairly arbitrary but keeps lines below 128 characters and so probably reduces the chances of buffer overflow.
|
| |
|
|
|
| |
It was actually possible to move the cursor anywhere on the screen, and it would wrap on all sides. Hitting "enter" would submit that (logical) line to the tokenizer. So, in the example pictured above (with "<code>PRUNT</code>", all that would be required for the fix was to move the cursor over the <code>U</code>, type <code>I</code> (the editor only had an overwrite mode) and then hit Enter. This was quite a frequent editing technique for, say, renumbering lines, since there was no built-in renumbering facility but quickly one could learn to, say, overwrite the numbers on a set of lines then just hit return repeatedly to enter them back into the program. Indeed, a slightly cryptic but essentially simple idiom allowed this to be done by the program itself as it was running, producing [[self-modifying code]]. This was not an artefact or cheat around the system but inherent in the combined behavior of the editor and tokenizer. |
|
It was actually possible to move the cursor anywhere on the screen, and it would wrap on all sides. Hitting "enter" would submit that (logical) line to the tokenizer. So, in the example pictured above (with "<code>PRUNT</code>", all that would be required for the fix was to move the cursor over the <code>U</code>, type <code>I</code> (the editor only had an overwrite mode) and then hit Enter. This was quite a frequent editing technique for, say, renumbering lines, since there was no built-in renumbering facility but quickly one could learn to, say, overwrite the numbers on a set of lines then just hit return repeatedly to enter them back into the program. Indeed, a slightly cryptic but essentially simple idiom allowed this to be done by the program itself as it was running, producing [[self-modifying code]]. This was not an artefact or cheat around the system but inherent in the combined behavior of the editor and tokenizer. |
| Line 61: |
Line 61: |
| |
The output from the tokenizer was then moved into more permanent storage in various locations in memory. A set of pointers (addresses) indicated these locations: variables were stored in the ''variable name table'' (pointed to at VNTP – 82, 83<sub>16</sub>) and the values were stored in the ''variable value table'' (pointed to at VVTP – 86, 87<sub>16</sub>). Strings had their own area (pointed to at STARP – 8C, 8D<sub>16</sub>) as did the runtime stack (pointed to at RUNSTK – 8E, 8F<sub>16</sub>) used to store the line numbers of looping statements (<code>FOR...NEXT</code>) and subroutines (<code>GOSUB...RETURN</code>). Finally, the end of BASIC memory usage was indicated by an address stored at MEMTOP – 90, 91<sub>16</sub>) pointer. |
|
The output from the tokenizer was then moved into more permanent storage in various locations in memory. A set of pointers (addresses) indicated these locations: variables were stored in the ''variable name table'' (pointed to at VNTP – 82, 83<sub>16</sub>) and the values were stored in the ''variable value table'' (pointed to at VVTP – 86, 87<sub>16</sub>). Strings had their own area (pointed to at STARP – 8C, 8D<sub>16</sub>) as did the runtime stack (pointed to at RUNSTK – 8E, 8F<sub>16</sub>) used to store the line numbers of looping statements (<code>FOR...NEXT</code>) and subroutines (<code>GOSUB...RETURN</code>). Finally, the end of BASIC memory usage was indicated by an address stored at MEMTOP – 90, 91<sub>16</sub>) pointer. |
| |
|
|
|
| - |
By [[indirection|indirecting]] the variable names in this way, a reference to a variable needed only two bytes to index its entry into the appropriate table; the whole name did not need to be stored each time. This also made variable renaming trivial if the program was in storage, as it was simply a case of changing the single instance of its name in the table: indeed, [[obfuscated code]] could be produced for a finished program by renaming variables in the name tables—possibly all to the same name. This didn't confuse the interpreter since internally it was using the index values not the names. Of course, new code would be difficult to add because the tokenizer had to translate names to indices, and could get confused if names were not unique (though it was OK to have names in both the string and 'variable' namespaces, e.g. <code>HELLO = 10</code> and <code>HELLO$ = "WORLD"</code>.)
|
+ |
By [[indirection|indirecting]] the variable names in this way, a reference to a variable needed only two bytes to index its entry into the appropriate table; the whole name did not need to be stored each time. This also made variable renaming trivial if the program was in storage, as it was simply a case of changing the single instance of its name in the table: indeed, [[obfuscated code]] could be produced for a finished program by renaming variables in the name tables – possibly all to the same name. This didn't confuse the interpreter since internally it was using the index values not the names. Of course, new code would be difficult to add because the tokenizer had to translate names to indices, and could get confused if names were not unique (though it was OK to have names in both the string and 'variable' namespaces, e.g. <code>HELLO = 10</code> and <code>HELLO$ = "WORLD"</code>.)
|
| |
|
|
|
| |
Atari BASIC used a unique system for abbreviating reserved words. Unlike Microsoft BASIC where there were a few "pre-rolled" short forms, (like <code>?</code> for <code>PRINT</code> and <code>'</code> for <code>REM</code>) Atari BASIC allowed any keyword to be abbreviated using a period. So <code>L.</code> would be expanded to <code>LIST</code>. To expand an abbreviation the tokenizer would search through its list of keywords (see below) and find the first that matched. To improve the probability of the programmer correctly guessing an abbreviation, and to save typing, the list of reserved words was sorted to place the more commonly used commands nearer the top. <code>REM</code> was at the very top, and could be typed in just as <code>.</code>. This also sped lexical analysis generally. In comparison, Microsoft BASIC used separate tokens for their few short forms, whereas Atari BASIC had only one token for each keyword – when the program was later <code>LIST</code>ed it would always write out the full words (since only one token represented all possible forms). |
|
Atari BASIC used a unique system for abbreviating reserved words. Unlike Microsoft BASIC where there were a few "pre-rolled" short forms, (like <code>?</code> for <code>PRINT</code> and <code>'</code> for <code>REM</code>) Atari BASIC allowed any keyword to be abbreviated using a period. So <code>L.</code> would be expanded to <code>LIST</code>. To expand an abbreviation the tokenizer would search through its list of keywords (see below) and find the first that matched. To improve the probability of the programmer correctly guessing an abbreviation, and to save typing, the list of reserved words was sorted to place the more commonly used commands nearer the top. <code>REM</code> was at the very top, and could be typed in just as <code>.</code>. This also sped lexical analysis generally. In comparison, Microsoft BASIC used separate tokens for their few short forms, whereas Atari BASIC had only one token for each keyword – when the program was later <code>LIST</code>ed it would always write out the full words (since only one token represented all possible forms). |
| Line 76: |
Line 76: |
| |
Atari BASIC differed dramatically from Microsoft-style BASICs in the way it handled strings. In BASICs following the Microsoft BASIC model, strings are special types that allow for variable length and various operations. Atari BASIC has no strings of this sort, instead using [[Array data structure|arrays]] of characters, rather like [[Fortran]]. This allowed the BASIC language programmers to remove all the special-purpose code needed for handling dynamic resizing of strings, reusing instead the code already being used to handle arrays of numbers. |
|
Atari BASIC differed dramatically from Microsoft-style BASICs in the way it handled strings. In BASICs following the Microsoft BASIC model, strings are special types that allow for variable length and various operations. Atari BASIC has no strings of this sort, instead using [[Array data structure|arrays]] of characters, rather like [[Fortran]]. This allowed the BASIC language programmers to remove all the special-purpose code needed for handling dynamic resizing of strings, reusing instead the code already being used to handle arrays of numbers. |
| |
|
|
|
| - |
Of course, strings are ''not'' used by end programmers in the same way as arrays of numbers — at least not normally — so Atari BASIC also included a selection of commands for "slicing" up arrays. <code>A$</code> referred to the entire string, whereas <code>A$(4,6)</code> "sliced" out the three characters 4, 5 and 6. In theory, this was a more elegant solution than Microsoft BASIC's <code>LEFT$</code>, <code>MID$</code>, and <code>RIGHT$</code> solution, as this syntax replaces three separate commands with a single one.
|
+ |
Of course, strings are ''not'' used by end programmers in the same way as arrays of numbers – at least not normally – so Atari BASIC also included a selection of commands for "slicing" up arrays. <code>A$</code> referred to the entire string, whereas <code>A$(4,6)</code> "sliced" out the three characters 4, 5 and 6. In theory, this was a more elegant solution than Microsoft BASIC's <code>LEFT$</code>, <code>MID$</code>, and <code>RIGHT$</code> solution, as this syntax replaces three separate commands with a single one.
|
| |
|
|
|
| |
Although this simplification reduced the size of Atari BASIC and offered some theoretical performance benefits, it also made it much more difficult to port BASIC programs onto the Atari, arguably more so than any other difference. Users would have to scan programs for instances of <code>LEFT$</code>, et al., and replace them with slicing commands. Also, strings were allocated a fixed size using the <code>DIM</code> command and the size could not be changed after. This generally meant the string sizes were over-allocated by the programmer to a [[guesstimate]] of their likely maximum size. |
|
Although this simplification reduced the size of Atari BASIC and offered some theoretical performance benefits, it also made it much more difficult to port BASIC programs onto the Atari, arguably more so than any other difference. Users would have to scan programs for instances of <code>LEFT$</code>, et al., and replace them with slicing commands. Also, strings were allocated a fixed size using the <code>DIM</code> command and the size could not be changed after. This generally meant the string sizes were over-allocated by the programmer to a [[guesstimate]] of their likely maximum size. |
| |
|
|
|
| - |
A common trick was to assign <code>MYSTRING$(1)</code> to <code>MYSTRING$(2)</code>, this would copy the same character from the first in the string into every position in the string, relying on the order of copying used in the Atari BASIC array copy routine — it was essentially [[undefined behavior]].
|
+ |
A common trick was to assign <code>MYSTRING$(1)</code> to <code>MYSTRING$(2)</code>, this would copy the same character from the first in the string into every position in the string, relying on the order of copying used in the Atari BASIC array copy routine – it was essentially [[undefined behavior]].
|
| |
|
|
|
| |
Strings in Atari BASIC were limited to one-dimensional arrays, so arrays of strings had to be implemented by the programmer. For short strings of approximately the same length, this was generally done by [[Padding_(cryptography)#Byte_padding|padding]] the strings so they are all the same length. According to Bill Wilkinson, a programmer at SMI, the decision to go with strings larger than 255 characters in size made string arrays unfeasible. |
|
Strings in Atari BASIC were limited to one-dimensional arrays, so arrays of strings had to be implemented by the programmer. For short strings of approximately the same length, this was generally done by [[Padding_(cryptography)#Byte_padding|padding]] the strings so they are all the same length. According to Bill Wilkinson, a programmer at SMI, the decision to go with strings larger than 255 characters in size made string arrays unfeasible. |
| Line 86: |
Line 86: |
| |
===Input/Output=== |
|
===Input/Output=== |
| |
====CIO overview==== |
|
====CIO overview==== |
| - |
The Atari [[operating system|OS]] included a subsystem for device input/output (I/O) known as CIO (Central Input/Output). All I/O went through a central point of entry (E45C<sub>16</sub>) passing the address of an ''I/O Control Block'' (IOCB), a structure that defined which device was meant, and what kind of operation (read, write, seek etc). It meant that most progams did not have to worry which device they were using, as they all conformed to a common interface— this was very rare on home computers at this time. Devices such as <code>S:</code> (the screen) and <code>E:<code> (the editor) did have special operations, for example to draw graphics or to ask for line input (in fact <code>E:</code> was pretty much a combination of <code>S:</code> and <code>K:</code>, the keyboard input device), but these were done in a uniform way and new device drivers could be written fairly easily that would automatically be available to BASIC and indeed any other program. using the Atari OS. Existing drivers could be supplanted or augmented by new ones since the driver table was searched newest-to-oldest, so a replacement <code>E:</code>, for example could displace the one in ROM to provide an 80-column display or to provide a [[checksum]] whenever a line was returned — this technique was used for some of the program listing checkers that provided a checksum for each line.
|
+ |
The Atari [[operating system|OS]] included a subsystem for device input/output (I/O) known as CIO (Central Input/Output). All I/O went through a central point of entry (E45C<sub>16</sub>) passing the address of an ''I/O Control Block'' (IOCB), a structure that defined which device was meant, and what kind of operation (read, write, seek etc). It meant that most progams did not have to worry which device they were using, as they all conformed to a common interface – this was very rare on home computers at this time. Devices such as <code>S:</code> (the screen) and <code>E:<code> (the editor) did have special operations, for example to draw graphics or to ask for line input (in fact <code>E:</code> was pretty much a combination of <code>S:</code> and <code>K:</code>, the keyboard input device), but these were done in a uniform way and new device drivers could be written fairly easily that would automatically be available to BASIC and indeed any other program. using the Atari OS. Existing drivers could be supplanted or augmented by new ones since the driver table was searched newest-to-oldest, so a replacement <code>E:</code>, for example could displace the one in ROM to provide an 80-column display or to provide a [[checksum]] whenever a line was returned – this technique was used for some of the program listing checkers that provided a checksum for each line.
|
| |
|
|
|
| |
====CIO access in BASIC==== |
|
====CIO access in BASIC==== |
| Line 129: |
Line 129: |
| |
In comparison to the BASICs of some competing machines at the time, Atari BASIC had good built-in support of sound, (<code>SOUND</code> statement), graphics (<code>GRAPHICS, SETCOLOR, COLOR, PLOT</code> and <code>DRAWTO</code>) and peripheral units like joysticks (<code>STICK, STRIG</code>) and paddles (<code>PADDLE, PTRIG</code>). Other home computer users were often left with cryptic <code>[[PEEK and POKE|POKE]]</code>s for such programming. |
|
In comparison to the BASICs of some competing machines at the time, Atari BASIC had good built-in support of sound, (<code>SOUND</code> statement), graphics (<code>GRAPHICS, SETCOLOR, COLOR, PLOT</code> and <code>DRAWTO</code>) and peripheral units like joysticks (<code>STICK, STRIG</code>) and paddles (<code>PADDLE, PTRIG</code>). Other home computer users were often left with cryptic <code>[[PEEK and POKE|POKE]]</code>s for such programming. |
| |
|
|
|
| - |
That being said, the parameters for many of these commands were cryptic, and essentially little better than machine code. <code>SOUND</code> took four numeric parameters for pitch, tone, volume and channel (the Atari 8-bits had 4-channel sound); the <code>GRAPHICS</code> statement took three to handle the numerous graphics modes, <code>SETCOLOR<code> and <code>COLOR</code> each took a number of parameters with different meanings depending on the graphics mode and often which did not match between the two, and so forth. It may be an example of [[Conway's law]]: clever designers made excellent hardware, by and large following a common model (memory-mapped register addressing for [[ANTIC]], GTIA and [[Atari POKEY|Pokey]], for example), but the lack of the teams' interaction made them work in curiously different ways. One may wonder why it would be thought so important to include two key words for examining the state of paddles — something that could be done easily with a single <code>PEEK</code> and indeed in every respect more efficiently than a <code>PADDLE</code> statement — yet not have a <code>FILL</code> command that was already coded in the OS and would have been uniquely advanced for the BASICs of the time.
|
+ |
That being said, the parameters for many of these commands were cryptic, and essentially little better than machine code. <code>SOUND</code> took four numeric parameters for pitch, tone, volume and channel (the Atari 8-bits had 4-channel sound); the <code>GRAPHICS</code> statement took three to handle the numerous graphics modes, <code>SETCOLOR<code> and <code>COLOR</code> each took a number of parameters with different meanings depending on the graphics mode and often which did not match between the two, and so forth. It may be an example of [[Conway's law]]: clever designers made excellent hardware, by and large following a common model (memory-mapped register addressing for [[ANTIC]], GTIA and [[Atari POKEY|Pokey]], for example), but the lack of the teams' interaction made them work in curiously different ways. One may wonder why it would be thought so important to include two key words for examining the state of paddles – something that could be done easily with a single <code>PEEK</code> and indeed in every respect more efficiently than a <code>PADDLE</code> statement – yet not have a <code>FILL</code> command that was already coded in the OS and would have been uniquely advanced for the BASICs of the time.
|
| |
|
|
|
| |
Similarly, advanced aspects of the hardware such as [[Sprite (computer graphics)|sprite]]s were completely out of bounds for BASIC programmers, and the lack of access to timers made sound programming difficult, particularly because North American machines ran on different [[clock speed]]s from the rest of the world (basically because they were tied to the speed of the television system). |
|
Similarly, advanced aspects of the hardware such as [[Sprite (computer graphics)|sprite]]s were completely out of bounds for BASIC programmers, and the lack of access to timers made sound programming difficult, particularly because North American machines ran on different [[clock speed]]s from the rest of the world (basically because they were tied to the speed of the television system). |
| Line 199: |
Line 199: |
| |
*{{cite|last=Wilkinson|first=Bill|title=The Atari BASIC Source Book|publisher=COMPUTE! Books|date=1983|isbn=0-942386-15-9|url=http://users.telenet.be/kim1-6502/6502/absb.html|publisher=Optimized Systems Software,Inc.|accessdate=2009-0404}} |
|
*{{cite|last=Wilkinson|first=Bill|title=The Atari BASIC Source Book|publisher=COMPUTE! Books|date=1983|isbn=0-942386-15-9|url=http://users.telenet.be/kim1-6502/6502/absb.html|publisher=Optimized Systems Software,Inc.|accessdate=2009-0404}} |
| |
*{{cite|last=Wilkinson|first=Bill|title=Inside Atari DOS|publisher=COMPUTE! Books|date=1982|isbn=0-942386-02-7|url=http://www.atariarchives.org/iad/introduction.php|publisher=Optimized Systems Software,Inc.|accessdate=2009-0404}} |
|
*{{cite|last=Wilkinson|first=Bill|title=Inside Atari DOS|publisher=COMPUTE! Books|date=1982|isbn=0-942386-02-7|url=http://www.atariarchives.org/iad/introduction.php|publisher=Optimized Systems Software,Inc.|accessdate=2009-0404}} |
| - |
*{{cite|url=http://www.atariarchives.org/dere/chapt10.php|title=De Re Atari|chapter=10: ATARI BASIC||publisher=AtariArchives.org|accessdate=2009-04-04}} — A detailed description of the dialect and interpreter
|
+ |
*{{cite|url=http://www.atariarchives.org/dere/chapt10.php|title=De Re Atari|chapter=10: ATARI BASIC||publisher=AtariArchives.org|accessdate=2009-04-04}} – A detailed description of the dialect and interpreter
|
| |
|
|
|
| |
== External links == |
|
== External links == |