jsbasic/reference.html
2022-01-29 10:19:28 -08:00

674 lines
30 KiB
HTML

<!DOCTYPE html>
<title>Applesoft BASIC Reference</title>
<meta charset="UTF-8">
<link rel="shortcut icon" href="favicon.ico">
<style>
@import url(https://fonts.googleapis.com/css?family=Coustard);
body { font-family: "Coustard"; }
body { background-color: #EEEACD; color: black; }
a { color: #803010; text-decoration: none; }
a:hover { text-decoration: underline; }
#toc { float: right; background-color: #DDDABD; font-size: 80%;}
code, .code, dt { font-family: 'Lucida Console', 'Courier New', Courier, monospace; font-weight: bold; color: #406040; }
h1 { margin-top: 0; }
h2 { border-top: solid 2px black; border-bottom: solid 2px black; }
pre.code { margin: 12pt; }
.nyi { opacity: 0.65; }
</style>
<div id="toc"></div>
<h1>Applesoft BASIC Quick Reference</h1>
<section id="intro">
<p>
This is intended as a quick reference for the <a href="./">Applesoft BASIC in JavaScript</a> by <a target=_blank href="mailto:inexorabletash@gmail.com">Joshua Bell</a>.
</p>
<p>
<a href="#extensions">Extensions</a> beyond Applesoft BASIC are called out with footnotes.
</p>
<p>See also:</p>
<ul>
<li><a href="http://www.landsnail.com/a2ref.htm">Apple II Programmer's Reference: Applesoft Commands</a>
<li><a href="http://www.apple2.org/faq/FAQ.applesoft.html">Applesoft BASIC Frequently Asked Questions (FAQ)</a>
<li><a href="http://www.lazilong.com/apple_II/bbros/">Beagle Bros. Peeks, Pokes & Pointers Chart (Colors, ASCII values, etc)</a>
<li><a href="http://beagle.applearchives.com/posters.htm">More Beagle Bros. Posters &mdash; including Apple Commands Chart, in PDF format</a>
<li><a href="http://www.scribd.com/doc/232832/Applesoft-Basic-Programming-Reference-Manual">Applesoft Basic Programming Reference Manual</a>
</ul>
</section>
<section id="statements">
<!-- ================================================== -->
<h2>Statements</h2>
<!-- ================================================== -->
<section>
<h3>Variable Control</h3>
<dl>
<dt>CLEAR<dd>Clear all variables
<dt>[LET] <var>var</var> = <var>expr</var><dd>Assign variable
<dt>DIM <var>var</var>( <var>size</var> [, <var>size</var> ...] ) [, <var>var</var>( <var>size</var> [, <var>size</var> ...] ) ...] <dd>Allocate array(s) with given dimension(s)
<dt>DEF FN <var>name</var>(<var>var</var>) = <var>aexpr</var><dd>Define function of a single variable <a href="#def_fn_string">[1]</a>
</dl>
</section>
<section>
<h3>Flow Control</h3>
<dl>
<dt>GOTO <var>linenum</var><dd>Jump to line number
<dt>GOSUB <var>linenum</var><dd>Enter subroutine at line number
<dt>RETURN<dd>Return from subroutine
<dt>ON <var>aexpr</var> GOTO <var>linenum</var> [, <var>linenum</var> ...]<dd>Branch based on index (value = 1, 2, ...)
<dt>ON <var>aexpr</var> GOSUB <var>linenum</var> [, <var>linenum</var> ...]<dd>Subroutine branch based on index (value = 1, 2, ...)
<dt>POP<dd>Convert last <code>GOSUB</code> into a <code>GOTO</code>
<dt>FOR <var>var</var> = <var>aexpr</var> TO <var>aexpr</var> [ STEP <var>aexpr</var> ]<dd>Loop with counter variable
<dt>NEXT [<var>var</var> [, <var>var</var> ...] ]<dd>End of loop(s)
<dt>IF <var>expr</var> THEN <var>statement</var>
<dt>IF <var>expr</var> GOTO <var>linenum</var><dd>Conditional; if <var>expr</var> is false, rest of line is skipped
<dt>END<dd>Terminate program cleanly
<dt>STOP<dd>Break, as if an error occurred
</dl>
</section>
<section>
<h3>Error Handling</h3>
<dl>
<dt>ONERR GOTO <var>linenum</var><dd>Set error hook
<dt>RESUME<dd>Retry line that caused <code>ONERR GOTO</code>
</dl>
</section>
<section>
<h3>Text Input/Output</h3>
<dl>
<dt>PRINT <var>expr</var> [ [;,] <var>expr</var> ... ] [;]<dd>Output text. <code>;</code> concatenates,
<code>,</code> advances to next tab stop. A trailing <code>;</code> suppresses line break.
<var>expr</var> can include <code>SPC(<var>aexpr</var>)</code> to advance by
multiple spaces, or <code>TAB(<var>aexpr</var>)</code> to advance to column.
<dt>INPUT [<var>string</var> ;] <var>var</var> [, <var>var</var> ...]<dd>Read line of comma-delimited input, with optional prompt
<dt>GET <var>var</var><dd>Read single key
<dt>HOME<dd>Clear text display
<dt>HTAB <var>aexpr</var><dd>Position text cursor horizontally (1...40 or 1...80)
<dt>VTAB <var>aexpr</var><dd>Position text cursor vertically (1...24)
<dt>INVERSE<dd>Set output mode to black-on-white
<dt>FLASH<dd>Set output mode to flashing
<dt>NORMAL<dd>Set output mode to white-on-black
<dt>TEXT<dd>Set display to text mode
</dl>
</section>
<section>
<h3>Lo-Res Graphics</h3>
<dl>
<dt>GR<dd>Set display to mixed test/low resolution ("lores") graphics mode, clear screen to black
<dt>COLOR= <var>aexpr</var><dd>Set lores color (0...15)
<dt>PLOT <var>aexpr</var>, <var>aexpr</var><dd>Plot lores point (x = 0...39, y = 0...39/47)
<dt>HLIN <var>aexpr</var>, <var>aexpr</var> AT <var>aexpr</var><dd>Plot horizontal line (x1, x2 at y)
<dt>VLIN <var>aexpr</var>, <var>aexpr</var> AT <var>aexpr</var><dd>Plot vertical line (y1, y2 at x)
</dl>
</section>
<section>
<h3>Hi-Res Graphics</h3>
<dl>
<dt>HGR<dd>Set display to mixed/high resolution ("hires") graphics mode, clear screen to black
<dt>HGR2<dd>Set display to full hires mode (page 2), clear screen to black
<dt>HPLOT [TO] <var>aexpr</var>, <var>aexpr</var> [ TO <var>aexpr</var>, <var>aexpr</var> ] ... <dd>Plot hires point/line (x=0...279, y=0...191)
<dt>HCOLOR= <var>aexpr</var><dd>Set hires color (0...7)
</dl>
</section>
<section>
<h3>Inline Data</h3>
<dl>
<dt>DATA <var>value</var> [, <var>value</var> ...]<dd>Define inline data. Values
can be literals (unquoted strings), strings, or numbers
<dt>READ <var>var</var> [, <var>var</var> ...]<dd>Read the next DATA value
<dt>RESTORE<dd>Restore the DATA pointer to the first value
</dl>
</section>
<section>
<h3>Miscellaneous</h3>
<dl>
<dt>REM [<var>comment</var>]<dd>Begin a comment; rest of line is skipped
<dt>TRACE<dd>Turn on trace mode (line numbers printed)
<dt>NOTRACE<dd>Turn off trace mode
</dl>
</section>
<section class="nyi">
<h3>Hi-Res Shape Tables <var>- NOT IMPLEMENTED</var></h3>
<dl>
<dt>ROT= <var>aexpr</var><dd>Set hires shape table rotation (0...63)
<dt>SCALE= <var>aexpr</var><dd>Set hires shape table scale (1...255)
<dt>DRAW <var>aexpr</var> [ AT <var>aexpr</var>, <var>aexpr</var> ]<dd>Draw hires shape table shape in color
<dt>XDRAW <var>aexpr</var> [ AT <var>aexpr</var>, <var>aexpr</var> ]<dd>Draw hires shape table shape with XOR
</dl>
</section>
<section class="nyi">
<h3>Interpreter and Program State <var>- NOT IMPLEMENTED</var></h3>
<dl>
<dt>CONT<dd>Continue from a STOP
<dt>DEL<dd>Delete lines of program
<dt>LIST [ <var>linenum</var> [, <var>linenum</var> ] ]<dd>List lines of program
<dt>NEW<dd>Clear program and variables
<dt>RUN [ <var>linenum</var> ]<dd>Start program execution at line
</dl>
</section>
<section class="nyi">
<h3>Native Platform Interaction <var>- NOT IMPLEMENTED</var></h3>
<dl>
<dt>HIMEM: <var>aexpr</var><dd>Set upper address of variable memory
<dt>IN# <var>aexpr</var><dd>Direct input from slot
<dt>LOMEM: <var>aexpr</var><dd>Set lower address of variable memory
<dt>WAIT <var>aexpr</var>, <var>aexpr</var> [, <var>aexpr</var>]<dd>Wait until memory location masked by second argument equals third argument (or zero)
</dl>
</section>
<section class="nyi">
<h3>Cassette Tape <var>- NOT IMPLEMENTED</var></h3>
<dl>
<dt>LOAD<dd>Load program from cassette
<dt>RECALL<dd>Load variables from cassette
<dt>SAVE<dd>Save program to cassette
<dt>STORE<dd>Save variables to cassette
<dt>SHLOAD<dd>Load hires shape table from cassette
</dl>
</section>
<section id="shims">
<h3>Compatibility Shims</h3>
<dl>
<dt>SPEED= <var>aexpr</var><dd>Set character output delay &mdash; <em>has no effect</em>
<dt>POKE <var>aexpr</var>, <var>aexpr</var><dd>Set memory location to value
<ul>
<li><code>POKE 32,<var>n</var></code> &mdash; Text window left edge
<li><code>POKE 33,<var>n</var></code> &mdash; Text window width
<li><code>POKE 34,<var>n</var></code> &mdash; Text window top edge
<li><code>POKE 35,<var>n</var></code> &mdash; Text window bottom
<li><code>POKE 36,<var>n</var></code> &mdash; Text cursor x
<li><code>POKE 37,<var>n</var></code> &mdash; Text cursor y
<li><code>POKE 216,<var>n</var></code> &mdash; ONERR flag (<var>n</var> &lt; 128 disables ONERR handler)
<li><code>POKE 230,<var>n</var></code> &mdash; Hi-Res plotting page (32 = page 1, 64 = page 2)
<li><code>POKE 49168,0</code> or <code>POKE -16368,0</code> &mdash; clear keyboard strobe
<li><code>POKE 49200,0</code> or <code>POKE -16336,0</code> &mdash; toggle speaker (no-op)
<li><code>POKE 49232,0</code> or <code>POKE -16304,0</code> &mdash; graphics mode
<li><code>POKE 49233,0</code> or <code>POKE -16303,0</code> &mdash; text mode
<li><code>POKE 49234,0</code> or <code>POKE -16302,0</code> &mdash; full graphics mode
<li><code>POKE 49235,0</code> or <code>POKE -16301,0</code> &mdash; mixed text/graphics mode
<li><code>POKE 49236,0</code> or <code>POKE -16300,0</code> &mdash; display page 1
<li><code>POKE 49237,0</code> or <code>POKE -16299,0</code> &mdash; display page 2
<li><code>POKE 49238,0</code> or <code>POKE -16298,0</code> &mdash; lores graphics mode
<li><code>POKE 49239,0</code> or <code>POKE -16297,0</code> &mdash; hires graphics mode
</ul>
<dt>CALL <var>aexpr</var><dd>Call native routine
<ul>
<li><code>CALL 54915</code> or <code>CALL -10621</code> &mdash; clear stack (pop all <code>FOR</code>/<code>NEXT</code>, <code>GOSUB</code>/<code>RETURN</code>, and <code>ONERR</code>/<code>RESUME</code> entries)
<li><code>CALL 62248</code> or <code>CALL -3288</code> &mdash; pop <code>ONERR</code>/<code>RESUME</code> entry from stack
<li><code>CALL 62436</code> or <code>CALL -3100</code> &mdash; reveal hi-res page 1
<li><code>CALL 62450</code> or <code>CALL -3086</code> &mdash; clear current hi-res page to black
<li><code>CALL 62454</code> or <code>CALL -3082</code> &mdash; clear current hi-res page to current color
<li><code>CALL 64500</code> or <code>CALL -1036</code> &mdash; move cursor right
<li><code>CALL 64528</code> or <code>CALL -1008</code> &mdash; move cursor left
<li><code>CALL 64538</code> or <code>CALL -998</code> &mdash; move cursor up
<li><code>CALL 64578</code> or <code>CALL -958</code> &mdash; clear text from cursor to bottom of window
<li><code>CALL 64614</code> or <code>CALL -922</code> &mdash; move cursor down
<li><code>CALL 64668</code> or <code>CALL -868</code> &mdash; clear text from cursor to end of line
<li><code>CALL 64780</code> or <code>CALL -756</code> &mdash; wait for keypress
<li><code>CALL 65152</code> or <code>CALL -384</code> &mdash; set inverse text mode
<li><code>CALL 65156</code> or <code>CALL -380</code> &mdash; set normal text mode
</ul>
<dt>PR# <var>aexpr</var><dd>Direct output to slot
<ul>
<li><code>PR#0</code> &mdash; set 40 column mode
<li><code>PR#3</code> &mdash; set 80 column mode
</ul>
</dl>
</section>
</section>
<section id="functions">
<!-- ================================================== -->
<h2>Functions</h2>
<!-- ================================================== -->
<h3>Numeric Functions</h3>
<dl>
<dt>ABS( <var>aexpr</var> )<dd>Absolute value of number
<dt>ATN( <var>aexpr</var> )<dd>Arctangent of number
<dt>COS( <var>aexpr</var> )<dd>Cosine of number
<dt>EXP( <var>aexpr</var> )<dd>Raise e to number
<dt>INT( <var>aexpr</var> )<dd>Integer part of number
<dt>LOG( <var>aexpr</var> )<dd>Natural log of number
<dt>RND( <var>aexpr</var> )<dd>Pseudo-random number generator.
If <var>aexpr</var> is positive, returns a random number from 0 to 0.999....
If <var>aexpr</var> is zero, repeats the last result.
If <var>aexpr</var> is negative, reseeds the generator.
<dt>SGN( <var>aexpr</var> )<dd>Sign of number (-1, 0, 1)
<dt>SIN( <var>aexpr</var> )<dd>Sine of number
<dt>SQR( <var>aexpr</var> )<dd>Square root of number
<dt>TAN( <var>aexpr</var> )<dd>Tangent of number
</dl>
<h3>String Functions</h3>
<dl>
<dt>LEN( <var>sexpr</var> )<dd>Length of string
<dt>LEFT$( <var>sexpr</var>, <var>aexpr</var> )<dd>Left portion of (string, length)
<dt>MID$( <var>sexpr</var>, <var>aexpr</var> [, <var>aexpr</var>] )<dd>Substring of (string, start character, length)
<dt>RIGHT$( <var>sexpr</var>, <var>aexpr</var> )<dd>Right portion of (string, length)
</dl>
<h3>Type Conversion Functions</h3>
<dl>
<dt>ASC( <var>sexpr</var> )<dd>ASCII code for first character of string
<dt>CHR$( <var>aexpr</var> )<dd>Character at specified ASCII code point <a href="#chr_extras">[3]</a>
<dt>STR$( <var>aexpr</var> )<dd>String representation of number
<dt>VAL( <var>sexpr</var> )<dd>Parse string into number
</dl>
<h3>System Interaction Functions</h3>
<dl>
<dt>FRE( <var>aexpr</var> )<dd>Garbage collect strings (returns 0)
<dt>PDL( <var>aexpr</var> )<dd>Paddle position (paddle number)
<dt>POS( <var>aexpr</var> )<dd>Horizontal cursor position
<dt>SCRN( <var>aexpr</var>, <var>aexpr</var> )<dd>Lores color at pixel (x,y) <a href="#hscrn">[4]</a>
<dt class="nyi">USR( <var>aexpr</var> )<dd class="nyi">Execute assembly code at address, return accumulator value <var>- NOT IMPLEMENTED</var>
</dl>
<h3>User Defined Functions</h3>
<dl>
<dt>FN <var>name</var>( <var>expr</var> )<dd>Execute user defined function <a href="#def_fn_string">[1]</a>
</dl>
<h3 id="function_shims">Function Compatibility Shims</h3>
<dl>
<dt id="peek">PEEK( <var>aexpr</var> )<dd>Value at memory location
<ul>
<li><code>PEEK(32)</code> &mdash; Text window left edge
<li><code>PEEK(33)</code> &mdash; Text window width
<li><code>PEEK(34)</code> &mdash; Text window top edge
<li><code>PEEK(35)</code> &mdash; Text window bottom
<li><code>PEEK(36)</code> &mdash; Text cursor x
<li><code>PEEK(37)</code> &mdash; Text cursor y
<li><code>PEEK(78)</code> &amp; <code>PEEK(79)</code> &mdash; Random-Number Field
<li><code>PEEK(222)</code> &mdash; Last error code
<li><code>PEEK(230)</code> &mdash; Hi-Res plotting page (32 = page 1, 64 = page 2)
<li><code>PEEK(49152)</code> or <code>PEEK(-16384)</code> &mdash; Read Keyboard
<li><code>PEEK(49168)</code> or <code>PEEK(-16368)</code> &mdash; Clear Keyboard strobe
<li><code>PEEK(49178)</code> or <code>PEEK(-16358)</code> &mdash; See if text mode (&gt; 127) or graphics mode (&lt; 128)
<li><code>PEEK(49179)</code> or <code>PEEK(-16357)</code> &mdash; See if mixed mode (&gt; 127) or full mode (&lt; 128)
<li><code>PEEK(49180)</code> or <code>PEEK(-16356)</code> &mdash; See if page2 (&gt; 127) or page1 (&lt; 128)
<li><code>PEEK(49181)</code> or <code>PEEK(-16355)</code> &mdash; See if hires mode (&gt; 127) or lores mode (&lt; 128)
<li><code>PEEK(49182)</code> or <code>PEEK(-16354)</code> &mdash; See if mousetext mode (&gt; 127)
<li><code>PEEK(49183)</code> or <code>PEEK(-16353)</code> &mdash; See if 80-column mode (&gt; 127)
<li><code>PEEK(49200)</code> or <code>PEEK(-16336)</code> &mdash; Click Speaker (no-op)
<li><code>PEEK(49248)</code> or <code>PEEK(-16288)</code> &mdash; Read Paddle Button #3 &mdash; <em>Use the PageDown key</em>
<li><code>PEEK(49249)</code> or <code>PEEK(-16287)</code> &mdash; Read Paddle Button #0 &mdash; <em>Use the Home key</em>
<li><code>PEEK(49250)</code> or <code>PEEK(-16286)</code> &mdash; Read Paddle Button #1 &mdash; <em>Use the End key</em>
<li><code>PEEK(49251)</code> or <code>PEEK(-16285)</code> &mdash; Read Paddle Button #2 &mdash; <em>Use the PageUp or Shift key</em>
</ul>
</dl>
</section>
<section id="operators">
<!-- ================================================== -->
<h2>Operators</h2>
<!-- ================================================== -->
<h3>Comparison Operators</h3>
<dl>
<dt>=<dd>Equality <a href="#eqeq">[2]</a>
<dt>&lt;<dd>Less than
<dt>&gt;<dd>Greater than
<dt>&lt;=<dt>=&lt;<dd>Less than or equal
<dt>&gt;=<dt>=&gt;<dd>Greater than or equal
<dt>&lt;&gt;<dt>&gt;&lt;<dd>Not equal
</dl>
<h3>Boolean Operators</h3>
<dl>
<dt>AND<dd>Conjunction
<dt>OR<dd>Disjunction
<dt>NOT<dd>Negation
</dl>
<h3>Arithmetic Operators</h3>
<dl>
<dt>^<dd>Exponentiation
<dt>*<dd>Multiplication
<dt>/<dd>Division
<dt>+<dd>Addition
<dt>-<dd>Subtraction
</dl>
<h3>String Operators</h3>
<dl>
<dt>+<dd>String Concatenation
</dl>
<h3>Operator Precedence</h3>
<p>Operators are listed vertically in order of precedence, from highest to lowest. Operators on the same line are of the same priority, and in an expression are executed from left to right. This order differs from the order in some other dialects of BASIC, but does match Applesoft.
<ul style="list-style-type: none">
<li><code>( )</code>
<li><code>+ - NOT</code> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (unary operators)
<li><code>^</code>
<li><code>* /</code>
<li><code>+ -</code>
<li><code>= &lt; &gt; &lt;= =&lt; &gt;= =&gt; &lt;&gt; &gt;&lt;</code>
<li><code>AND</code>
<li><code>OR</code>
</ul>
</section>
<section id="errorcodes">
<!-- ================================================== -->
<h2>Error Codes</h2>
<!-- ================================================== -->
<p>Error codes can be determined by calling
<code>PEEK(222)</code> in an ONERR handler.</p>
<dl>
<dt>0<dd>Next without for
<dt>16<dd>Syntax error &mdash; <em>Not generated</em>
<dt>22<dd>Return without gosub
<dt>42<dd>Out of data
<dt>53<dd>Illegal quantity
<dt>69<dd>Overflow
<dt>77<dd>Out of memory &mdash; <em>Not generated by all browsers</em>
<dt>90<dd>Undefined statement
<dt>107<dd>Bad subscript
<dt>120<dd>Redimensioned array
<dt>133<dd>Division by zero
<dt>163<dd>Type mismatch
<dt>176<dd>String too long &mdash; <em>Not generated</em>
<dt>191<dd>Formula too complex &mdash; <em>Not generated by all browsers</em>
<dt>224<dd>Undefined function
<dt>254<dd>Re-enter
<dt>255<dd>Break
</dl>
</section>
<section id="dos">
<!-- ================================================== -->
<h2>DOS 3.3 / ProDOS Quick Reference</h2>
<!-- ================================================== -->
<p>See also</p>
<ul>
<li><a href="http://www.xs4all.nl/~fjkraan/comp/apple2faq/app2doscmdfaq.html">Apple II DOS &amp; Commands FAQ</a>
<li><a href="http://www.textfiles.com/apple/ANATOMY/">Apple II Textfiles: the DOS 3.3 Anatomy</a>
<li><a href="http://vectronicsappleworld.com/appleii/dos.html">Vectronic's Apple World DOS 3.3 and ProDOS Guide</a>
</ul>
<h3>DOS Commands</h3>
<dl>
<dt>MON[,C][,I][,O]<dd>Traces DOS 3.3 commands ('Commands', 'Input' and 'Output')
<dt>NOMON[,C][,I][,O] <dd>Cancels tracing of DOS 3.3 commands ('Commands', 'Input' and 'Output')
<dt>OPEN <var>filename</var>[,L<var>len</var>] <dd>Opens a text file.
<dt>APPEND <var>filename</var> <dd>Appends to a text file.
<dt>CLOSE [<var>filename</var>] <dd>Closes specified (or all) open text files.
<dt>POSITION <var>filename</var>[,R<var>num</var>] <dd>Advances position in text file.
<dt>READ <var>filename</var>[,R<var>num</var>][,B<var>byte</var>] <dd>Reads from a text file.
<dt>WRITE <var>filename</var>[,R<var>num</var>][,B<var>byte</var>]<dd>Writes to a text file
<dt>DELETE <var>filename</var> <dd>Delete a file
<dt>RENAME <var>oldname</var>,<var>newname</var> <dd>Rename a file
<dt>PR# <var>slot</var> <dd>Same as the BASIC command
</dl>
<p><var>Other DOS commands are NOT IMPLEMENTED.</var></p>
<p>Some sample files are present in a server-side store loaded on-demand into a client-side virtual file system (VFS). Creating or writing to a file will write to the VFS. Subsequent reads will read from the VFS. Files may be deleted from the VFS. These changes will not persist if the browser is refreshed or closed.</p>
<h3>DOS Error Codes</h3>
<p>Error codes can be determined by calling
<code>PEEK(222)</code> in an ONERR handler.</p>
<dl>
<dt>1<dd>Language not available &mdash; <em>Not generated</em>
<dt>2<dd>Range error &mdash; <em>Not generated</em>
<dt>4<dd>Write protected &mdash; <em>Not generated</em>
<dt>5<dd>End of data
<dt>6<dd>File not found
<dt>7<dd>Volume mismatch &mdash; <em>Not generated</em>
<dt>8<dd>I/O error &mdash; <em>Not generated</em>
<dt>9<dd>Disk full &mdash; <em>Not generated</em>
<dt>10<dd>File locked &mdash; <em>Not generated</em>
<dt>11<dd>Invalid option
<dt>12<dd>No buffers available &mdash; <em>Not generated</em>
<dt>13<dd>File type mismatch &mdash; <em>Not generated</em>
<dt>14<dd>Program too large &mdash; <em>Not generated</em>
<dt>15<dd>Not direct command &mdash; <em>Not generated</em>
</dl>
</section>
<section id="io">
<!-- ================================================== -->
<h2>Input and Output</h2>
<!-- ================================================== -->
<h3>Input</h3>
<p>
The page attempts to emulate an Apple II keyboard. Note that the keyboard
API available in Web browsers is not standardized and is poorly defined;
a best-effort has been made testing on available systems and browsers.
</p>
<p>
The <em>Open Apple</em> and <em>Closed Apple</em> keys on later Apple II models
correspond to the Button #0 and Button #1 inputs and are emulated on modern keyboards
with the <em>Left Alt</em> and <em>Right Alt</em> keys respectively if possible,
otherwise the <em>Home</em> and <em>End</em> keys respectively.
</p>
<p>
Since the <em>Tab</em> key is necessary for keyboard access to browser functions and
the rest of the web page, it is not available. Otherwise, special keys can be detected
using <code>GET</code> (blocking) or <code>PEEK(49152)</code> or <code>PEEK(-16384)</code> (non-blocking):
</p>
<table style="margin-left: 3em;">
<tr><td><code>CHR$(8)</code><td>Left arrow
<tr><td><code>CHR$(10)</code><td>Down arrow
<tr><td><code>CHR$(11)</code><td>Up arrow
<tr><td><code>CHR$(13)</code><td>Enter or Return
<tr><td><code>CHR$(21)</code><td>Right arrow
<tr><td><code>CHR$(24)</code><td>Clear
<tr><td><code>CHR$(27)</code><td>Escape
<tr><td><code>CHR$(127)</code><td>Delete or Backspace
</table>
<h3>Output</h3>
<p>
The page attempts to emulate the display of an Apple II system with
80-column card firmware, which can be activated with the
<code>PR#3</code> statement.
</p>
<p>
When printing characters, <code>CHR$()</code> functions as expected for values
from 32-126 (printable ASCII). Control characters have the typical Apple II meanings:
</p>
<table style="margin-left: 3em;">
<tr><td><code>CHR$(4)</code><td>DOS command escape prefix
<tr><td><code>CHR$(7)</code><td>Make a "beep" (if your browser supports it)
<tr><td><code>CHR$(8)</code><td>Backspace (move cursor left, wrap up)
<tr><td><code>CHR$(10)</code><td>Line feed (move cursor down)
<tr><td><code>CHR$(13)</code><td>Carriage return (move cursor down and to left edge)
<tr><td><code>CHR$(127)</code><td>Displays a cursor glyph
</table>
<p>
If 80-column firmware is active, the following additional codes are available:
</p>
<table style="margin-left: 3em;">
<tr><td><code>CHR$(11)</code><td>Clears from the cursor position to the end of the window
<tr><td><code>CHR$(12)</code><td>Move cursor to upper left and clear window
<tr><td><code>CHR$(14)</code><td>Set normal text output
<tr><td><code>CHR$(15)</code><td>Set inverse text output
<tr><td><code>CHR$(17)</code><td>Set display to 40 columns
<tr><td><code>CHR$(18)</code><td>Set display to 80 columns
<tr><td><code>CHR$(21)</code><td>Deactivate the 80-column firmware
<tr><td><code>CHR$(22)</code><td>Scroll display down, preserving cursor position
<tr><td><code>CHR$(23)</code><td>Scroll display up, preserving cursor position
<tr><td><code>CHR$(24)</code><td>Disable mousetext
<tr><td><code>CHR$(25)</code><td>Move cursor to upper left (but do not clear window)
<tr><td><code>CHR$(26)</code><td>Clear the current line
<tr><td><code>CHR$(27)</code><td>Enable mousetext
<tr><td><code>CHR$(28)</code><td>Forward space (move cursor right, wrap down)
<tr><td><code>CHR$(29)</code><td>Clear from cursor position to end of line
</table>
<p>
The text window can be changed and cursor finely controlled
with <code>POKE 32,<var>n</var></code> ... <code>POKE 37,<var>n</var></code>
</p>
</section>
<section id="grammar">
<!-- ================================================== -->
<h2>Process and Grammars</h2>
<!-- ================================================== -->
<p><em>For the even geekier in the audience...</em></p>
<p>Compilation is done by splitting the input into tokens which are then
consumed by a recursive descent parser which outputs a JavaScript
object representing the program.</p>
<p>The token types (treated as terminals) are
<code>reserved</code>,
<code>identifier</code>,
<code>string-literal</code>,
<code>number-literal</code> <a href="#hex">[5]</a>,
<code>operator</code>,
<code>line-number</code>,
<code>separator</code>,
<code>remark</code>,
<code>data-declaration</code>
&mdash; take a peek at the code if you want the gruesome details. Source lines may
only start with line numbers or (as an extension) separators. Special statement
parsing is done while lexing: <code>REM</code> consumes anything to the next
line break, and <code>DATA</code> statements yield an array of strings
from the comma-delimited, optionally-quoted values in the source.
</p>
<dl>
<dt>[x]<dd> zero or one occurences of x
<dt>{x}<dd> zero or more occurences of x
<dt>x|y<dd> one of either x or y
<dt>(x)<dd> grouping construct
</dl>
<p>Overall program parsing is done with a recursive descent parser.</p>
<pre class="code">
Program = Line { Line }
Line = line-number Statement { separator Statement }
Statement = data-declaration | remark | Command | EmptyStatement
Command = identifier /*...*/ | reserved /*...*/
</pre>
<p>Due to the irregular structure of the BASIC language, statements ("commands" in the above grammar)
are parsed with distinct cases for each statement type.
Most statements compile into a function call to a library of Applesoft routines. Expressions are parsed
with a standard recursive descent parser. The parser generates JavaScript expressions for each expression,
which are used as arguments for the library calls.</p>
<pre class="code">
Expression = OrExpression
OrExpression = AndExpression { 'OR' AndExpression }
AndExpression = RelationalExpression { 'AND' RelationalExpression }
RelationalExpression = AdditiveExpression { ('=' | '&lt;' | '&gt;' | '&lt;=' | '=&lt;' | '&gt;=' | '=&gt;' | '&lt;&gt;' | '&gt;&lt;') AdditiveExpression }
AdditiveExpression = MultiplicativeExpression { ( '+' | '-' ) MultiplicativeExpression }
MultiplicativeExpression = PowerExpression { ( '*' | '/' ) PowerExpression }
PowerExpression = UnaryExpression { '^' UnaryExpression }
UnaryExpression = ( '+' | '-' | 'NOT' ) UnaryExpression
| FinalExpression
FinalExpression = number-literal
| string-literal
| 'FN' user_function_name '(' Expression ')'
| reserved '(' Expression { ',' Expression } ')'
| identifier [ '(' Expression { ',' Expression } ')' ]
| '(' Expression ')'
</pre>
<p>Since Applesoft supports re-entrant error handling and synchronous input,
the output of the compiler is an array of statement-functions plus an executor
function which implements the logic for walking over the array.<p>
</section>
<section id="extensions">
<!-- ================================================== -->
<h2>Extensions beyond Standard Applesoft</h2>
<!-- ================================================== -->
<ol>
<li id="def_fn_string">
<code>DEF FN</code> supports string and integer functions
e.g. <code>DEF FN IN$(X$) = " " + X$</code>
&mdash; the return type must match the argument type, so string-to-number or number-to-string functions
can not be implemented.
<li id="eqeq">
"Double equals" <code>==</code> is supported for equality comparisons, with the same meaning as "single equals" <code>=</code>
<li id="chr_extras">
When printing characters, <code>CHR$()</code> values greater than 255 generate glyphs that might be useful for implementing certain maze games. <em>(An earlier version of this page allowed arbitrary Unicode characters to be displayed, but the text is now displayed using bitmaps so that is not possible.)</em>
<li id="hscrn">
<code>HSCRN(<var>x</var>,<var>y</var>)</code> is added to allow reading the
hires screen. On a real Apple II this required a machine-language routine (or a shape table and <code>XDRAW</code>) and
extensive knowledge of the Apple II's color generation scheme.
<li id="hex">
Hexadecimal number literals are permitted, with <code>$</code> as a prefix, e.g. <code>POKE $C010, 0</code>
</ol>
</section>
<script src="https://cdn.rawgit.com/inexorabletash/polyfill/v0.1.29/polyfill.min.js"></script>
<script>
(function buildTOC(el) {
var html = [];
el.innerHTML = "";
var level = 1, unique = 1;
[].forEach.call(document.querySelectorAll('h2, h3'), function(c) {
var newLevel = parseInt(c.nodeName.charAt(1), 10);
if (newLevel > level) {
html.push('<ol>');
} else if (level > newLevel) {
html.push('</ol>');
}
level = newLevel;
function makeID(string) {
var id = String(string).replace(/[^a-zA-Z0-9]/g, '-');
while (document.getElementById(id))
id += '_' + unique++;
id = id.replace(/-+/g, '-');
return id;
}
var key = makeID(c.textContent);
html.push('<li><a href="#' + key + '">' + c.innerHTML + '</a>');
c.id = key;
});
while( level > 1 ) {
html.push( '</ol>' );
--level;
}
el.innerHTML = html.join('');
}(document.getElementById('toc')));
</script>