Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

Share the Microsoft BASIC for 6502 source code written by Bill Gates


Jun 02, 2021 Article blog




TITLE   BASIC M6502 8K VER 1.1 BY MICRO-SOFT
SEARCH  M6502
SALL
RADIX 10            ;THROUGHOUT ALL BUT MATH-PAK.

$Z:: ;STARTING POINT FOR M6502 SIMULATOR ORG 0 ;START OFF AT LOCATION ZERO. SUBTTL SWITCHES,MACROS.

REALIO=4 ;5=STM ;4=APPLE. ;3=COMMODORE. ;2=OSI ;1=MOS TECH,KIM ;0=PDP-10 SIMULATING 6502 INTPRC==1 ;INTEGER ARRAYS. ADDPRC==1 ;FOR ADDITIONAL PRECISION. LNGERR==0 ;LONG ERROR MESSAGES. TIME== 0 ;CAPABILITY TO SET AND READ A CLK. EXTIO== 0 ;EXTERNAL I/O. DISKO== 0 ;SAVE AND LOAD COMMANDS NULCMD==1 ;FOR THE "NULL" COMMAND GETCMD==1 RORSW==1 ROMSW==1 ;TELLS IF THIS IS ON ROM. CLMWID==14 LONGI==1 ;LONG INITIALIZATION SWITCH. STKEND=511 BUFPAG==0 LINLEN==72 ;TERMINAL LINE LENGTH. BUFLEN==72 ;INPUT BUFFER SIZE. ROMLOC= ^O20000 ;ADDRESS OF START OF PURE SEGMENT. KIMROM=1 IFE ROMSW,<KIMROM==0> IFN REALIO-1,<KIMROM==0> IFN ROMSW,< RAMLOC= ^O40000 ;USED ONLY IF ROMSW=1 IFE REALIO,<ROMLOC= ^O20000 ;START AT 8K. RAMLOC=^O1400>> IFE REALIO-3,< DISKO==1 RAMLOC==^O2000 ROMLOC=^O140000 NULCMD==0 GETCMD==1 linlen==40 BUFLEN==81 CQOPEN=^O177700 CQCLOS=^O177703 CQOIN= ^O177706 ;OPEN CHANNEL FOR INPUT CQOOUT=^O177711 ;FILL FOR COMMO. CQCCHN=^O177714 CQINCH=^O177717 ;INCHR'S CALL TO GET A CHARACTER OUTCH= ^O177722 CQLOAD=^O177725 CQSAVE=^O177730 CQVERF=^O177733 CQSYS= ^O177736 ISCNTC=^O177741 CZGETL=^O177744 ;CALL POINT FOR "GET" CQCALL=^O177747 ;CLOSE ALL CHANNELS CQTIMR=^O215 BUFPAG==2 BUF==256BUFPAG STKEND==507 CQSTAT=^O226 CQHTIM=^O164104 EXTIO==1 TIME==1 GETCMD==1 CLMWID==10 PI=255 ;VALUE OF PI CHARACTER FOR COMMODORE. ROMSW==1 RORSW==1 TRMPOS=^O306> IFE REALIO-1,<GETCMD==1 DISKO==1 OUTCH=^O17240 ;1EA0 ROMLOC==^O20000 RORSW==0 CZGETL=^O17132> IFE REALIO-2,< RORSW==0 RAMLOC==^O1000 IFN ROMSW,< RORSW==0 RAMLOC==^O100000> OUTCH==^O177013> IFE REALIO-4,< RORSW==1 NULCMD==0 GETCMD==1 CQINLN==^O176547 CQPRMP==^O63 CQINCH==^O176414 CQCOUT==^O177315 CQCSIN==^O177375 BUFPAG==2 BUF=BUFPAG256 ROMLOC=^O4000 RAMLOC=^O25000 ;PAGE 2A OUTCH=^O176755 CZGETL=^O176414 LINLEN==40 BUFLEN==240 RORSW==1 STKEND=507> IFE RORSW,< DEFINE ROR (WD),< LDAI 0 BCC .+4 LDAI ^O200 LSR WD ORA WD STA WD>>

DEFINE ACRLF,< 13 10> DEFINE SYNCHK (Q),< LDAI <Q> JSR SYNCHR> DEFINE DT(Q),< IRPC Q,<IFDIF <Q><">,<EXP "Q">>> DEFINE LDWD (WD),< LDA WD LDY <WD>+1> DEFINE LDWDI (WD),< LDAI <<WD>&^O377> LDYI <<WD>/^O400>> DEFINE LDWX (WD),< LDA WD LDX <WD>+1> DEFINE LDWXI (WD),< LDAI <<WD>&^O377> LDXI <<WD>/^O400>> DEFINE LDXY (WD),< LDX WD LDY <WD>+1> DEFINE LDXYI (WD),< LDXI <<WD>&^O377> LDYI <<WD>/^O400>> DEFINE STWD (WD),< STA WD STY <WD>+1> DEFINE STWX (WD),< STA WD STX <WD>+1> DEFINE STXY (WD),< STX WD STY <WD>+1> DEFINE CLR (WD),< LDAI 0 STA WD> DEFINE COM (WD),< LDA WD EORI ^O377 STA WD> DEFINE PULWD (WD),< PLA STA WD PLA STA <WD>+1> DEFINE PSHWD (WD),< LDA <WD>+1 PHA LDA WD PHA> DEFINE JEQ (WD),< BNE .+5 JMP WD> DEFINE JNE (WD),< BEQ .+5 JMP WD> DEFINE BCCA(Q),< BCC Q> ;BRANCHES THAT ALWAYS BRANCH DEFINE BCSA(Q),< BCS Q> ;THESE ARE USED ON THE 6502 BECAUSE DEFINE BEQA(Q),< BEQ Q> ;THERE IS NO UNCONDITIONAL BRANCH DEFINE BNEA(Q),< BNE Q> DEFINE BMIA(Q),< BMI Q> DEFINE BPLA(Q),< BPL Q> DEFINE BVCA(Q),< BVC Q> DEFINE BVSA(Q),< BVS Q> DEFINE INCW(R),< INC R BNE %Q INC R+1 %Q:> DEFINE SKIP1, <XWD ^O1000,^O044> ;BIT ZERO PAGE TRICK. DEFINE SKIP2, <XWD ^O1000,^O054> ;BIT ABS TRICK. IF1,< IFE REALIO,<PRINTX/SIMULATE/> IFE REALIO-1,<PRINTX KIM> IFE REALIO-2,<PRINTX OSI> IFE REALIO-3,<PRINTX COMMODORE> IFE REALIO-4,<PRINTX APPLE> IFE REALIO-5,<PRINTX STM> IFN ADDPRC,<PRINTX ADDITIONAL PRECISION> IFN INTPRC,<PRINTX INTEGER ARRAYS> IFN LNGERR,<PRINTX LONG ERRORS> IFN DISKO,<PRINTX SAVE AND LOAD> IFE ROMSW,<PRINTX RAM> IFN ROMSW,<PRINTX ROM> IFE RORSW,<PRINTX NO ROR> IFN RORSW,<PRINTX ROR ASSUMED>> PAGE SUBTTL INTRODUCTION AND COMPILATION PARAMETERS. COMMENT *


COPYRIGHT 1976 BY MICROSOFT


7/27/78 FIXED BUG WHERE FOR VARIABLE AT BYTE FF MATCHED RETURN SEARCHING FOR GOSUB ENTRY ON STACK IN FNDFOR CALL BY CHANGING STA FORPNT TO STA FORPNT+1. THIS IS A SERIOUS BUG IN ALL VERSIONS. 7/27/78 FIXED BUG AT NEWSTT UNDER IFN BUFPAG WHEN CHECK OF CURLIN WAS DONE BEFORE CURLIN SET UP SO INPUT RETRIES OF FIRST STATEMENT WAS GIVING SYNTAX ERROR INSTEAD OF REDO FROM START (CODE WAS 12/1/77 FIX) 7/1/78 SAVED A FEW BYTES IN INIT FOR COMMODORE (14) 7/1/78 FIXED BUG WHERE REPLACING A LINE OVERFLOWING MEMORY LEFT LINKS IN A BAD STATE. (CODE AT NODEL AND FINI) BUG#4 7/1/78 FIXED BUG WHERE GARBAGE COLLECTION NEVER(!) COLLECTS TEMPS (STY GRBPNT AT FNDVAR, LDA GRBPNT ORA GRBPNT+1 AT GRBPAS) THIS WAS COMMODORE BUG #2 7/1/78 FIXED BUG WHERE DELETE/INSERT OF LINE COULD CAUSE A GARBAGE COLLECTION WITH BAD VARTAB IF OUT OF MEMORY (LDWD MEMSIZ STWD FRETOP=JSR RUNC CLC ALSO AT NODEL) 3/9/78 EDIT TO FIX COMMO TRMPOS AND CHANGE LEFT$ AND RIGHT$ TO ALLOW A SECOND ARGUMENT OF 0 AND RETURN A NULL STRING 2/25/78 FIXED BUG THAT INPFLG WAS SET WRONG WHEN BUFPAG.NE.0 INCREASED NUMLEV FROM 19 TO 23 2/11/78 DISALLOWED SPACES IN RESERVED WORDS. PUT IN SPECIAL CHECK FOR "GO TO" 2/11/78 FIXED BUG WHERE ROUNDING OF THE FAC BEFORE PUSHING COULD CAUSE A STRING POINTER IN THE FAC TO BE INCREMENTED 1/24/78 fixed problem where user defined function undefined check fix was smashing error number in [x] 12/1/77 FIXED PROBLEM WHERE PEEK WAS SMASHING (POKER) CAUSING POKE OF PEEK TO FAIL 12/1/77 FIXED PROBLEM WHERE PROBLEM WITH VARTXT=LINNUM=BUF-2 CAUSING BUF-1 COMMA TO DISAPPEAR 12/1/77 FIXED BUFPAG.NE.0 PROBLEM AT NEWSTT AND STOP : CODE WAS STILL ASSUMING TXTPTR+1.EQ.0 IFF STATEMENT WAS DIRECT * NUMLEV==23 ;NUMBER OF STACK LEVELS RESERVED ;BY AN EXPLICIT CALL TO "GETSTK". STRSIZ==3 ;# OF LOCS PER STRING DESCRIPTOR. NUMTMP==3 ;NUMBER OF STRING TEMPORARIES. CONTW==15 ;CHARACTER TO SUPPRESS OUTPUT.

PAGE SUBTTL SOME EXPLANATION. COMMENT *

M6502 BASIC CONFIGURES BASIC AS FOLLOWS

LOW LOCATIONS PAGE ZERO

    STARTUP:
    INITIALLY A JMP TO INITIALIZATION CODE BUT
    CHANGED TO A JMP TO &quot;READY&quot;.
    RESTARTING THE MACHINE AT LOC 0 DURING PROGRAM
    EXECUTION CAN LEAVE THINGS MESSED UP.

    LOC OF FAC TO INTEGER AND INTEGER TO FAC 
    ROUTINES.

    &quot;DIRECT&quot; MEMORY:
    THESE ARE THE MOST COMMONLY USED LOCATIONS.
    THEY HOLD BOOKKEEPING INFO AND ALL OTHER
    FREQUENTLY USED INFORMATION.
    ALL TEMPORARIES, FLAGS, POINTERS, THE BUFFER AREA,
    THE FLOATING ACCUMULATOR, AND ANYTHING ELSE THAT
    IS USED TO STORE A CHANGING VALUE SHOULD BE LOCATED
    IN THIS AREA. CARE MUST BE MADE IN MOVING LOCATIONS
    IN THIS AREA SINCE THE JUXTAPOSITION OF TWO LOCATIONS
    IS OFTEN DEPENDED UPON.

    STILL IN RAM WE HAVE THE BEGINNING OF THE &quot;CHRGET&quot;
    SUBROUTINE. IT IS HERE SO [TXTPTR] CAN BE THE
    EXTENDED ADDRESS OF A LOAD INSTRUCTION.
    THIS SAVES HAVING TO BOTHER ANY REGISTERS.

PAGE    ONE
    THE STACK.

STORAGE PAGE TWO AND ON
    IN RAM VERSIONS THESE DATA STRUCTURES COME AT THE
    END OF BASIC. IN ROM VERSON THEY ARE AT RAMLOC WHICH
    CAN EITHER BE ABOVE OR BELOW ROMLOC, WHICH IS WHERE
    BASIC ITSELF RESIDES.

            A ZERO.
    [TXTTAB]    POINTER TO NEXT LINE'S POINTER.
            LINE # OF THIS LINE (2 BYTES).
            CHARACTERS ON THIS LINE.
            ZERO.
            POINTER AT NEXT LINE'S POINTER
                (POINTED TO BY THE ABOVE POINTER).
            ... REPEATS ...
    LAST LINE:  POINTER AT ZERO POINTER.
            LINE # OF THIS LINE.
            CHARACTERS ON THIS LINE.
            ZERO.
            DOUBLE ZERO (POINTED TO BY THE ABOVE POINTER).
    [VARTAB]    SIMPLE VARIABLES. 6 BYTES PER VALUE.
            2 BYTES GIVE THE NAME, 4 BYTES THE VALUE.
            ... REPEATS ...
    [ARYTAB]    ARRAY VARIABLES. 2 BYTES NAME, 2 BYTE
            LENGTH, NUMBER OF DIMENSIONS , EXTENT OF
            EACH DIMENSION (2BYTES/), VALUES
            ... REPEATS ...
    [STREND]    FREE SPACE.
            ... REPEATS ...
    [FRETOP]    STRING SPACE IN USE.
            ... REPEATS ...
    [MEMSIZ]    HIGHEST MACHINE LOCATION.
            UNUSED EXCEPT BY THE VAL FUNCTION.

    ROM -- CONSTANTS AND CODE.

FUNCTION DISPATCH ADDRESSES (AT ROMLOC)
    &quot;FUNDSP&quot; CONTAINS THE ADDRESSES OF THE
    FUNCTION ROUTINES IN THE ORDER OF THE
    FUNCTION NAMES IN THE CRUNCH LIST.
    THE FUNCTIONS THAT TAKE MORE THAN ONE ARGUMENT
    ARE AT THE END. SEE THE EXPLANATION AT &quot;ISFUN&quot;.

THE OPERATOR LIST
    THE &quot;OPTAB&quot; LIST CONTAINS AN OPERATOR'S PRECEDENCE
    FOLLOWED BY THE ADDRESS OF THE ROUTINE TO PERFORM
    THE OPERATION. THE INDEX INTO THE
    OPERATOR LIST IS MADE BY SUBTRACTING OFF THE CRUNCH VALUE
    OF THE LOWEST NUMBERED OPERATOR. THE ORDER
    OF OPERATORS IN THE CRUNCH LIST AND IN &quot;OPTAB&quot; IS IDENTICAL.
    THE PRECEDENCES ARE ARBITRARY EXCEPT FOR THEIR
    COMPARATIVE SIZES. NOTE THAT THE PRECEDENCE FOR
    UNARY OPERATORS SUCH AS &quot;NOT&quot; AND NEGATION ARE
    SETUP SPECIALLY WITHOUT USING THE LIST.

THE RESERVED WORD OR CRUNCH LIST
    WHEN A COMMAND OR PROGRAM LINE IS TYPED IN
    IT IS STORED IN &quot;BUF&quot;. AS SOON AS THE WHOLE LINE
    HAS BEEN TYPED IN (&quot;INLIN&quot; RETURNS) &quot;CRUNCH&quot; IS
    CALLED TO CONVERT ALL RESERVED WORDS TO THEIR
    CRUNCHED VALUES. THIS REDUCES THE SIZE OF THE 
    PROGRAM AND SPEEDS UP EXECUTION BY ALLOWING
    LIST DISPATCHES TO PERFORM FUNCTIONS, STATEMENTS,
    AND OPERATIONS. THIS IS BECAUSE ALL THE STATEMENT
    NAMES ARE STORED CONSECUTIVELY IN THE CRUNCH LIST.
    WHEN A MATCH IS FOUND BETWEEN A STRING
    OF CHARACTERS AND A WORD IN THE CRUNCH LIST
    THE ENTIRE TEXT OF THE MATCHED WORD IS TAKEN OUT OF
    THE INPUT LINE AND A RESERVED WORD TOKEN IS PUT
    IN ITS PLACE. A RESERVED WORD TOKEN IS ALWAYS EQUAL
    TO OCTAL 200 PLUS THE POSITION OF THE MATCHED WORD
    IN THE CRUNCH LIST.

STATEMENT DISPATCH ADDRESSES
    WHEN A STATEMENT IS TO BE EXECUTED, THE FIRST
    CHARACTER OF THE STATEMENT IS EXAMINED
    TO SEE IF IT IS LESS THAN THE RESERVED
    WORD TOKEN FOR THE LOWEST NUMBERED STATEMENT NAME.
    IF SO, THE &quot;LET&quot; CODE IS CALLED TO
    TREAT THE STATEMENT AS AN ASSIGNMENT STATEMENT.
    OTHERWISE A CHECK IS MADE TO MAKE SURE THE
    RESERVED WORD NUMBER IS NOT TOO LARGE TO BE A
    STATEMENT TYPE NUMBER. IF NOT THE ADDRESS
    TO DISPATCH TO IS FETCHED FROM &quot;STMDSP&quot; (THE STATEMENT
    DISPATCH LIST) USING THE RESERVED WORD
    NUMBER FOR THE STATEMENT TO CALCULATE AN INDEX INTO
    THE LIST.

ERROR MESSAGES
    WHEN AN ERROR CONDITION IS DETECTED,
    [ACCX] MUST BE SET UP TO INDICATE WHICH ERROR
    MESSAGE IS APPROPRIATE AND A BRANCH MUST BE MADE
    TO &quot;ERROR&quot;. THE STACK WILL BE RESET AND ALL
    PROGRAM CONTEXT WILL BE LOST. VARIABLES
    VALUES AND THE ACTUAL PROGRAM REMAIN INTACT.
    ONLY THE VALUE OF [ACCX] IS IMPORTANT WHEN
    THE BRANCH IS MADE TO ERROR. [ACCX] IS USED AS AN
    INDEX INTO &quot;ERRTAB&quot; WHICH GIVES THE TWO
    CHARACTER ERROR MESSAGE THAT WILL BE PRINTED ON THE
    USER'S TERMINAL.


TEXTUAL MESSAGES
    CONSTANT MESSAGES ARE STORED HERE. UNLESS
    THE CODE TO CHECK IF A STRING MUST BE COPIED
    IS CHANGED THESE STRINGS MUST BE STORED ABOVE
    PAGE ZERO, OR ELSE THEY WILL BE COPIED BEFORE
    THEY ARE PRINTED.

FNDFOR  
    MOST SMALL ROUTINES ARE FAIRLY SIMPLE
    AND ARE DOCUMENTED IN PLACE. &quot;FNDFOR&quot; IS
    USED FOR FINDING &quot;FOR&quot; ENTRIES ON
    THE STACK. WHENEVER A &quot;FOR&quot; IS EXECUTED, A
    16-BYTE ENTRY IS PUSHED ONTO THE STACK.
    BEFORE THIS IS DONE, HOWEVER, A CHECK
    MUST BE MADE TO SEE IF THERE
    ARE ANY &quot;FOR&quot; ENTRIES ALREADY ON THE STACK
    FOR THE SAME LOOP VARIABLE. IF SO, THAT &quot;FOR&quot; ENTRY
    AND ALL OTHER &quot;FOR&quot; ENTRIES THAT WERE MADE AFTER IT
    ARE ELIMINATED FROM THE STACK. THIS IS SO A
    PROGRAM THAT JUMPS OUT OF THE MIDDLE
    OF A &quot;FOR&quot; LOOP AND THEN RESTARTS THE LOOP AGAIN
    AND AGAIN WON'T USE UP 18 BYTES OF STACK
    SPACE EVERY TIME. THE &quot;NEXT&quot; CODE ALSO
    CALLS &quot;FNDFOR&quot; TO SEARCH FOR A &quot;FOR&quot; ENTRY WITH
    THE LOOP VARIABLE IN
    THE &quot;NEXT&quot;. AT WHATEVER POINT A MATCH IS FOUND
    THE STACK IS RESET. IF NO MATCH IS FOUND A
    &quot;NEXT WITHOUT FOR&quot;  ERROR OCCURS. GOSUB EXECUTION
    ALSO PUTS A 5-BYTE ENTRY ON STACK.
    WHEN A RETURN IS EXECUTED &quot;FNDFOR&quot; IS
    CALLED WITH A VARIABLE POINTER THAT CAN'T
    BE MATCHED. WHEN &quot;FNDFOR&quot; HAS RUN
    THROUGH ALL THE &quot;FOR&quot; ENTRIES ON THE STACK  
    IT RETURNS AND THE RETURN CODE MAKES
    SURE THE ENTRY THAT WAS STOPPED
    ON IS A GOSUB ENTRY. THIS ASSURES THAT
    IF YOU GOSUB TO A SECTION OF CODE
    IN WHICH A FOR LOOP IS ENTERED BUT NEVER
    EXITED THE RETURN WILL STILL BE
    ABLE TO FIND THE MOST RECENT
    GOSUB ENTRY. THE &quot;RETURN&quot; CODE ELIMINATES THE
    &quot;GOSUB&quot; ENTRY AND ALL &quot;FOR&quot; ENTRIES MADE AFTER
    THE GOSUB ENTRY.

NON-RUNTIME STUFF
    THE CODE TO INPUT A LINE, CRUNCH IT, GIVE ERRORS,
    FIND A SPECIFIC LINE IN THE PROGRAM,
    PERFORM A &quot;NEW&quot;, &quot;CLEAR&quot;, AND &quot;LIST&quot; ARE
    ALL IN THIS AREA. GIVEN THE EXPLANATION OF
    PROGRAM STORAGE SET FORTH ABOVE, THESE ARE
    ALL STRAIGHTFORWARD.

NEWSTT
    WHENEVER A STATEMENT FINISHES EXECUTION IT
    DOES A &quot;RTS&quot; WHICH TAKES
    EXECUTION BACK TO &quot;NEWSTT&quot;. STATEMENTS THAT
    CREATE OR LOOK AT SEMI-PERMANENT STACK ENTRIES
    MUST GET RID OF THE RETURN ADDRESS OF &quot;NEWSTT&quot; AND
    JMP TO &quot;NEWSTT&quot; WHEN DONE. &quot;NEWSTT&quot; ALWAYS
    CHRGETS THE FIRST CHARACTER AFTER THE STATEMENT
    NAME BEFORE DISPATCHING. WHEN RETURNING
    BACK TO &quot;NEWSTT&quot; THE ONLY THING THAT
    MUST BE SET UP IS THE TEXT POINTER IN
    &quot;TXTPTR&quot;. &quot;NEWSTT&quot; WILL CHECK TO MAKE SURE
    &quot;TXTPTR&quot; IS POINTING TO A STATEMENT TERMINATOR.
    IF A STATEMENT SHOULDN'T BE PERFORMED UNLESS
    IT IS PROPERLY FORMATTED (I.E. &quot;NEW&quot;) IT CAN
    SIMPLY DO A RETURN AFTER READING ALL OF
    ITS ARGUMENTS. SINCE THE ZERO FLAG
    BEING OFF INDICATES THERE IS NOT
    A STATEMENT TERMINATOR &quot;NEWSTT&quot; WILL
    DO THE JMP TO THE &quot;SYNTAX ERROR&quot;
    ROUTINE. IF A STATEMENT SHOULD BE STARTED
    OVER IT CAN DO LDWD OLDTXT, STWD TXTPTR RTS SINCE THE TEXT PNTR
    AT &quot;NEWSTT&quot; IS ALWAYS STORED IN &quot;OLDTXT&quot;.
    THE ^C CODE STORES [CURLIN] (THE
    CURRENT LINE NUMBER) IN &quot;OLDLIN&quot; SINCE THE ^C CHECK
    IS MADE BEFORE THE STATEMENT POINTED TO IS
    EXECUTED. &quot;STOP&quot; AND &quot;END&quot; STORE THE TEXT POINTER
    FROM &quot;TXTPTR&quot;, WHICH POINTS AT THEIR TERMINATING
    CHARACTER, IN &quot;OLDTXT&quot;.

STATEMENT CODE
    THE INDIVIDUAL STATEMENT CODE COMES
    NEXT. THE APPROACH USED IN EXECUTING EACH
    STATEMENT IS DOCUMENTED IN THE STATEMENT CODE
    ITSELF.

FRMEVL, THE FORMULA EVALUATOR
    GIVEN A TEXT POINTER POINTING TO THE STARTING
    CHARACTER OF A FORMULA, &quot;FRMEVL&quot;
    EVALUATES THE FORMULA AND LEAVES
    THE VALUE IN THE FLOATING ACCUMULATOR (FAC).
    &quot;TXTPTR&quot; IS RETURNED POINTING TO THE FIRST CHARACTER
    THAT COULD NOT BE INTERPRETED AS PART OF THE
    FORMULA. THE ALGORITHM USES THE STACK
    TO STORE TEMPORARY RESULTS:

        0. PUT A DUMMY PRECEDENCE OF ZERO ON
            THE STACK.
        1. READ LEXEME (CONSTANT,FUNCTION,
            VARIABLE,FORMULA IN PARENS)
            AND TAKE THE LAST PRECEDENCE VALUE
            OFF THE STACK.
        2. SEE IF THE NEXT CHARACTER IS AN OPERATOR.
            IF NOT, CHECK PREVIOUS ONE. THIS MAY CAUSE
            OPERATOR APPLICATION OR AN ACTUAL
            RETURN FROM &quot;FRMEVL&quot;.
        3. IF IT IS, SEE WHAT PRECEDENCE IT HAS
            AND COMPARE IT TO THE PRECEDENCE
            OF THE LAST OPERATOR ON THE STACK.
        4. IF = OR LESS REMEMBER THE OPERATOR
            POINTER OF THIS OPERATOR
            AND BRANCH TO &quot;QCHNUM&quot; TO CAUSE
            APPLICATION OF THE LAST OPERATOR.
            EVENTUALLY RETURN TO STEP 2
            BY RETURNING TO JUST AFTER &quot;DOPREC&quot;.
        5. IF GREATER PUT THE LAST PRECEDENCE
            BACK ON, SAVE THE OPERATOR ADDRESS,
            CURRENT TEMPORARY RESULT,
            AND PRECEDENCE AND RETURN TO STEP 1.

    RELATIONAL OPERATORS ARE ALL HANDLED THROUGH
    A COMMON ROUTINE. SPECIAL
    CARE IS TAKEN TO DETECT TYPE MISMATCHES SUCH AS 3+&quot;F&quot;.

EVAL -- THE ROUTINE TO READ A LEXEME
    &quot;EVAL&quot; CHECKS FOR THE DIFFERENT TYPES OF
    ENTITIES IT IS SUPPOSED TO DETECT.
    LEADING PLUSES ARE IGNORED,
    DIGITS AND &quot;.&quot; CAUSE &quot;FIN&quot; (FLOATING INPUT)
    TO BE CALLED. FUNCTION NAMES CAUSE THE
    FORMULA INSIDE THE PARENTHESES TO BE EVALUATED
    AND THE FUNCTION ROUTINE TO BE CALLED. VARIABLE
    NAMES CAUSE &quot;PTRGET&quot; TO BE CALLED TO GET A POINTER
    TO THE VALUE, AND THEN THE VALUE IS PUT INTO
    THE FAC. AN OPEN PARENTHESIS CAUSES &quot;FRMEVL&quot;
    TO BE CALLED (RECURSIVELY), AND THE &quot;)&quot; TO
    BE CHECKED FOR. UNARY OPERATORS (NOT AND
    NEGATION)  PUT THEIR PRECEDENCE ON THE STACK
    AND ENTER FORMULA EVALUATION AT STEP 1, SO
    THAT EVERYTHING UP TO AN OPERATOR GREATER THAN
    THEIR PRECEDENCE OR THE END OF THE FORMULA
    WILL BE EVALUATED.

DIMENSION AND VARIABLE SEARCHING
    SPACE IS ALLOCATED FOR VARIABLES AS THEY ARE
    ENCOUNTERED. THUS &quot;DIM&quot; STATEMENTS MUST BE
    EXECUTED TO HAVE EFFECT. 6 BYTES ARE ALLOCATED
    FOR EACH SIMPLE VARIABLE, WHETHER IT IS A STRING,
    NUMBER OR USER DEFINED FUNCTION. THE FIRST TWO
    BYTES GIVE THE NAME OF THE VARIABLE AND THE LAST FOUR
    GIVE ITS VALUE. [VARTAB] GIVES THE FIRST LOCATION
    WHERE A SIMPLE VARIABLE NAME IS FOUND AND [ARYTAB]
    GIVES THE LOCATION TO STOP SEARCHING FOR SIMPLE
    VARIABLES. A &quot;FOR&quot; ENTRY HAS A TEXT POINTER
    AND A POINTER TO A VARIABLE VALUE SO NEITHER
    THE PROGRAM OR THE SIMPLE VARIABLES CAN BE
    MOVED WHILE THERE ARE ACTIVE &quot;FOR&quot; ENTRIES ON THE STACK.
    USER DEFINED FUNCTION VALUES ALSO CONTAIN
    POINTERS INTO SIMPLE VARIABLE SPACE SO NO USER-DEFINED
    FUNCTION VALUES CAN BE RETAINED IF SIMPLE VARIABLES
    ARE MOVED. ADDING A SIMPLE VARIABLE IS JUST
    ADDING SIX TO [ARYTAB] AND [STREND], BLOCK TRANSFERING
    THE ARRAY VARIABLES UP BY SIX AND MAKING SURE THE
    NEW [STREND] IS NOT TOO CLOSE TO THE STRINGS.
    THIS MOVEMENT OF ARRAY VARIABLES MEANS
    THAT NO POINTER TO AN ARRAY WILL STAY VALID WHEN
    NEW SIMPLE VARIABLES CAN BE ENCOUNTERED. THIS IS
    WHY ARRAY VARIABLES ARE NOT ALLOWED FOR &quot;FOR&quot;
    LOOP VARIABLES. SETTING UP A NEW ARRAY VARIABLE
    MERELY INVOLVES BUILDING THE DESCRIPTOR,
    UPDATING [STREND], AND MAKING SURE THERE IS
    STILL ENOUGH ROOM BETWEEN [STREND] AND STRING SPACE.
    &quot;PTRGET&quot;, THE ROUTINE WHICH RETURNS A POINTER
    TO A VARIABLE VALUE, HAS TWO IMPORTANT FLAGS. ONE IS
    &quot;DIMFLG&quot; WHICH INDICATES WHETHER &quot;DIM&quot; CALLED &quot;PTRGET&quot;
    OR NOT. IF SO, NO PRIOR ENTRY FOR THE VARIABLE IN
    QUESTION SHOULD BE FOUND, AND THE INDEX INDICATES
    HOW MUCH SPACE TO SET ASIDE. SIMPLE VARIABLES CAN
    BE &quot;DIMENSIONED&quot;, BUT THE ONLY EFFECT WILL BE TO
    SET ASIDE SPACE FOR THE VARIABLE IF IT HASN'T BEEN
    ENCOUNTERED YET. THE OTHER IMPORTANT FLAG IS &quot;SUBFLG&quot;
    WHICH INDICATES WHETHER A SUBSCRIPTED VARIABLE SHOULD BE
    ALLOWED IN THE CURRENT CONTEXT. IF [SUBFLG] IS NON-ZERO
    THE OPEN PARENTHESIS FOR A SUBSCRIPTED VARIABLE
    WILL NOT BE SCANNED BY &quot;PTRGET&quot;, AND &quot;PTRGET&quot; WILL RETURN
    WITH A TEXT POINTER POINTING TO THE &quot;(&quot;, IF
    THERE WAS ONE.
STRINGS
    IN THE VARIABLE TABLES STRINGS ARE STORED JUST LIKE
    NUMERIC VARIABLES. SIMPLE STRINGS HAVE THREE VALUE
    BYTES WHICH ARE INITIALIZED TO ALL ZEROS (WHICH
    REPRESENTS THE NULL STRING). THE ONLY DIFFERENCE
    IN HANDLING IS THAT WHEN &quot;PTRGET&quot; SEES A &quot;$&quot; AFTER THE
    NAME OF A VARIABLE, &quot;PTRGET&quot; SETS [VALTYP]
    TO NEGATIVE ONE AND TURNS
    ON THE MSB (MOST-SIGNIFIGANT-BIT) OF THE VALUE OF
    THE FIRST CHARACTER OF THE VARIABLE NAME.
    HAVING THIS BIT ON IN THE NAME OF THE VARIABLE ENSURES
    THAT THE SEARCH ROUTINE WILL NOT MATCH
    'A' WITH 'A$' OR 'A$' WITH 'A'. THE MEANING OF
    THE THREE VALUE BYTES ARE:
        LOW
            LENGTH OF THE STRING
            LOW 8 BITS
            HIGH 8 BITS  OF THE ADDRESS
                OF THE CHARACTERS IN THE
                STRING IF LENGTH.NE.0.
                MEANINGLESS OTHERWISE.
        HIGH
    THE VALUE OF A STRING VARIABLE (THESE 3 BYTES)
    IS CALLED THE STRING DESCRIPTOR TO DISTINGUISH
    IT FROM THE ACTUAL STRING DATA. WHENEVER A
    STRING CONSTANT IS ENCOUNTERED IN A FORMULA OR AS
    PART OF AN INPUT STRING, OR AS PART OF DATA, &quot;STRLIT&quot;
    IS CALLED, CAUSING A DESCRIPTOR TO BE BUILT FOR
    THE STRING. WHEN ASSIGNMENT IS MADE TO A STRING POINTING INTO
    &quot;BUF&quot; THE VALUE IS COPIED INTO STRING SPACE SINCE [BUF]
    IS ALWAYS CHANGING.

    STRING FUNCTIONS AND THE ONE STRING OPERATOR &quot;+&quot;
    ALWAYS RETURN THEIR VALUES IN STRING SPACE.
    ASSIGNING A STRING A CONSTANT VALUE IN A PROGRAM
    THROUGH A &quot;READ&quot; OR ASSIGNMENT STATEMENT
    WILL NOT USE ANY STRING SPACE SINCE
    THE STRING DESCRIPTOR  WILL POINT INTO THE
    PROGRAM ITSELF. IN GENERAL, COPYING IS DONE
    WHEN A STRING VALUE IS IN &quot;BUF&quot;, OR IT IS IN STRING
    SPACE AND THERE IS AN ACTIVE POINTER TO IT.
    THUS F$=G$ WILL CAUSE COPYING IF G$ HAS ITS
    STRING DATA IN STRING SPACE. F$=CHR$(7)
    WILL USE ONE BYTE OF STRING SPACE TO STORE THE
    NEW ONE CHARACTER STRING CREATED BY &quot;CHR$&quot;, BUT
    THE ASSIGNMENT ITSELF WILL CAUSE NO COPYING SINCE
    THE ONLY POINTER AT THE NEW STRING IS A
    TEMPORARY DESCRIPTOR CREATED BY &quot;FRMEVL&quot; WHICH WILL
    GO AWAY AS SOON AS THE ASSIGNMENT IS DONE.
    IT IS THE NATURE OF GARBAGE COLLECTION THAT
    DISALLOWS HAVING TWO STRING DESCRIPTORS POINT TO THE SAME
    AREA IN STRING SPACE. STRING FUNCTIONS AND OPERATORS
    MUST PROCEED AS FOLLOWS:
        1) FIGURE OUT THE LENGTH OF THEIR RESULT.

        2) CALL &quot;GETSPA&quot; TO FIND SPACE FOR THEIR
        RESULT. THE ARGUMENTS TO THE FUNCTION
        OR OPERATOR MAY CHANGE SINCE GARBAGE COLLECTION
        MAY BE INVOKED. THE ONLY THING THAT CAN
        BE SAVED DURING THE CALL TO &quot;GETSPA&quot; IS A POINTER
        TO THE DESCRIPTORS OF THE ARGUMENTS.
        3) CONSTRUCT THE RESULT DESCRIPTOR IN &quot;DSCTMP&quot;.
        &quot;GETSPA&quot; RETURNS THE LOCATION OF THE AVAILABLE
        SPACE.
        4) CREATE THE NEW VALUE BY COPYING PARTS
        OF THE ARGUMENTS OR WHATEVER.
        5) FREE UP THE ARGUMENTS BY CALLING &quot;FRETMP&quot;.
        6) JUMP TO &quot;PUTNEW&quot; TO GET THE DESCRIPTOR IN
        &quot;DSCTMP&quot; TRANSFERRED INTO A NEW STRING TEMPORARY.

    THE REASON FOR STRING TEMPORARIES IS THAT GARBAGE
    COLLECTION HAS TO KNOW ABOUT ALL ACTIVE STRING DESCRIPTORS
    SO IT KNOWS WHAT IS AND ISN'T IN USE. STRING TEMPORARIES ARE
    USED TO STORE THE DESCRIPTORS OF STRING EXPRESSIONS.

    INSTEAD OF HAVING AN ACTUAL VALUE STORED IN THE
    FAC, AND HAVING THE VALUE OF A TEMPORARY RESULT
    BEING SAVED ON THE STACK, AS HAPPENS WITH NUMERIC
    VARIABLES, STRINGS HAVE THE POINTER TO A STRING DESCRIPTOR
    STORED IN THE FAC, AND IT IS THIS POINTER
    THAT GETS SAVED ON THE STACK BY FORMULA EVALUATION.
    STRING FUNCTIONS CANNOT FREE THEIR ARGUMENTS UP RIGHT
    AWAY SINCE &quot;GETSPA&quot; MAY FORCE
    GARBAGE COLLECTION AND THE ARGUMENT STRINGS
    MAY BE OVER-WRITTEN SINCE GARBAGE COLLECTION
    WILL NOT BE ABLE TO FIND AN ACTIVE POINTER TO
    THEM. FUNCTION AND OPERATOR RESULTS ARE BUILT IN
    &quot;DSCTMP&quot; SINCE STRING TEMPORARIES ARE ALLOCATED
    (PUTNEW) AND DEALLOCATED (FRETMP) IN A FIFO ORDERING
    (I.E. A STACK) SO THE NEW TEMPORARY CANNOT
    BE SET UP UNTIL THE OLD ONE(S) ARE FREED. TRYING
    TO BUILD A RESULT IN A TEMPORARY AFTER
    FREEING UP THE ARGUMENT TEMPORARIES COULD RESULT
    IN ONE OF THE ARGUMENT TEMPORARIES BEING OVERWRITTEN
    TOO SOON BY THE NEW RESULT.

    STRING SPACE IS ALLOCATED AT THE VERY TOP
    OF MEMORY. &quot;MEMSIZ&quot; POINTS BEYOND THE LAST LOCATION OF
    STRING SPACE. STRINGS ARE STORED IN HIGH LOCATIONS
    FIRST. WHENEVER STRING SPACE IS ALLOCATED (GETSPA).
    [FRETOP], WHICH IS INITIALIZED TO [MEMSIZ], IS UPDATED
    TO GIVE THE HIGHEST LOCATION IN STRING SPACE
    THAT IS NOT IN USE. THE RESULT IS THAT
    [FRETOP] GETS SMALLER AND SMALLER, UNTIL SOME
    ALLOCATION WOULD MAKE [FRETOP] LESS THAN OR EQUAL TO
    [STREND]. THIS MEANS STRING SPACE HAS RUN INTO THE
    THE ARRAYS AND THAT GARBAGE COLLECTION MUST BE CALLED.

    GARBAGE COLLECTION:
        0. [MINPTR]=[STREND] [FRETOP]=[MEMSIZ]
        1. [REMMIN]=0
        2. FOR EACH STRING DESCRIPTOR
        (TEMPORARIES, SIMPLE STRINGS, STRING ARRAYS)
        IF THE STRING IS NOT NULL AND ITS POINTER IS
        .GT.MINPTR AND .LT.FRETOP,
        [MINPTR]=THIS STRING DESCRIPTOR'S POINTER,
        [REMMIN]=POINTER AT THIS STRING DESCRIPTOR.
        END.
        3. IF REMMIN.NE.0 (WE FOUND AN UNCOLLECTED STRING),
        BLOCK TRANSFER THE STRING DATA POINTED
        TO IN THE STRING DESCRIPTOR POINTED TO BY &quot;REMMIN&quot;
        SO THAT THE LAST BYTE OF STRING DATA IS AT
        [FRETOP]. UPDATE [FRETOP] SO THAT IT
        POINTS TO THE LOCATION JUST BELOW THE ONE
        THE STRING DATA WAS MOVED INTO. UPDATE
        THE POINTER IN THE DESCRIPTOR SO IT POINTS
        TO THE NEW LOCATION OF THE STRING DATA.
        GO TO STEP 1.

    AFTER CALLING GARBAGE COLLECTION &quot;GETSPA&quot; AGAIN CHECKS
    TO SEE IF [ACCA] CHARACTERS ARE AVAILABLE BETWEEN
    [STREND] AND [FRETOP]; IF NOT, AN &quot;OUT OF STRING&quot;
    ERROR IS INVOKED.

MATH PACKAGE
    THE MATH PACKAGE CONTAINS FLOATING INPUT (FIN),
    FLOATING OUTPUT (FOUT), FLOATING COMPARE (FCOMP)
    ... AND ALL THE NUMERIC OPERATORS AND FUNCTIONS.
    THE FORMATS, CONVENTIONS AND ENTRY POINTS ARE ALL
    DESCRIBED IN THE MATH PACKAGE ITSELF.

INIT -- THE INITIALIZATION ROUTINE
    THE AMOUNT OF MEMORY,
    TERMINAL WIDTH, AND WHICH FUNCTIONS TO BE RETAINED
    ARE ASCERTAINED FROM THE USER. A ZERO IS PUT DOWN
    AT THE FIRST LOCATION NOT USED BY THE MATH-PACKAGE
    AND [TXTTAB] IS SET UP TO POINT AT THE NEXT LOCATION.
    THIS DETERMINES WHERE PROGRAM STORAGE WILL START.
    SPECIAL CHECKS ARE MADE TO MAKE SURE
    ALL QUESTIONS IN &quot;INIT&quot; ARE ANSWERED REASONABLY, SINCE
    ONCE &quot;INIT&quot; FINISHES, THE LOCATIONS IT USES ARE
    USED FOR PROGRAM STORAGE. THE LAST THING &quot;INIT&quot; DOES IS
    CHANGE LOCATION ZERO TO BE A JUMP TO &quot;READY&quot; INSTEAD
    OF &quot;INIT&quot;. ONCE THIS IS DONE THERE IS NO WAY TO RESTART
    &quot;INIT&quot;.

HIGH LOCATIONS

* PAGE SUBTTL PAGE ZERO. IFN REALIO-3,< START: JMP INIT ;INITIALIZE - SETUP CERTAIN LOCATIONS ;AND DELETE FUNCTIONS IF NOT NEEDED, ;AND CHANGE THIS TO "JMP READY" ;IN CASE USER RESTARTS AT LOC ZERO. RDYJSR: JMP INIT ;CHANGED TO "JMP STROUT" BY "INIT" ;TO HANDLE ERRORS. ADRAYI: ADR(AYINT) ;STORE HERE THE ADDR OF THE ;ROUTINE TO TURN THE FAC INTO A ;TWO BYTE SIGNED INTEGER IN [Y,A] ADRGAY: ADR(GIVAYF)> ;STORE HERE THE ADDR OF THE ;ROUTINE TO CONVERT [Y,A] TO A FLOATING ;POINT NUMBER IN THE FAC. IFN ROMSW,< USRPOK: JMP FCERR> ;SET UP ORIG BY INIT. ; ; THIS IS THE "VOLATILE" STORAGE AREA AND NONE OF IT ; CAN BE KEPT IN ROM. ANY CONSTANTS IN THIS AREA CANNOT ; BE KEPT IN A ROM, BUT MUST BE LOADED IN BY THE ; PROGRAM INSTRUCTIONS IN ROM. ; ; --- GENERAL RAM ---: CHARAC: BLOCK 1 ;A DELIMITING CHARACTER. INTEGR= CHARAC ;A ONE-BYTE INTEGER FROM "QINT". ENDCHR: BLOCK 1 ;THE OTHER DELIMITING CHARACTER. COUNT: BLOCK 1 ;A GENERAL COUNTER.

; --- FLAGS ---: DIMFLG: BLOCK 1 ;IN GETTING A POINTER TO A VARIABLE ;IT IS IMPORTANT TO REMEMBER WHETHER IT ;IS BEING DONE FOR "DIM" OR NOT. ;DIMFLG AND VALTYP MUST BE ;CONSECUTIVE LOCATIONS. KIMY= DIMFLG ;PLACE TO PRESERVE Y DURING OUT. VALTYP: BLOCK 1 ;THE TYPE INDICATOR. ;0=NUMERIC 1=STRING. IFN INTPRC,< INTFLG: BLOCK 1> ;TELLS IF INTEGER. DORES: BLOCK 1 ;WHETHER CAN OR CAN'T CRUNCH RES'D WORDS. ;TURNED ON WHEN "DATA" ;BEING SCANNED BY CRUNCH SO UNQUOTED ;STRINGS WON'T BE CRUNCHED. GARBFL= DORES ;WHETHER TO DO GARBAGE COLLECTION. SUBFLG: BLOCK 1 ;FLAG WHETHER SUB'D VARIABLE ALLOWED. ;"FOR" AND USER-DEFINED FUNCTION ;POINTER FETCHING TURN ;THIS ON BEFORE CALLING "PTRGET" ;SO ARRAYS WON'T BE DETECTED. ;"STKINI" AND "PTRGET" CLEAR IT. ;ALSO DISALLOWS INTEGERS THERE. INPFLG: BLOCK 1 ;FLAGS WHETHER WE ARE DOING "INPUT" ;OR "READ". TANSGN: BLOCK 1 ;USED IN DETERMINING SIGN OF TANGENT. IFN REALIO,< CNTWFL: BLOCK 1> ;SUPPRESS OUTPUT FLAG. ;NON-ZERO MEANS SUPPRESS. ;RESET BY "INPUT", READY AND ERRORS. ;COMPLEMENTED BY INPUT OF ^O.

IFE REALIO-4,<ORG 80> ;ROOM FOR APPLE PAGE 0 STUFF. ; --- RAM DEALING WITH TERMINAL HANDLING ---: IFN EXTIO,< CHANNL: BLOCK 1> ;HOLDS CHANNEL NUMBER. IFN NULCMD,< NULCNT: 0> ;NUMBER OF NULLS TO PRINT. IFN REALIO-3,< TRMPOS: BLOCK 1> ;POSITION OF TERMINAL CARRIAGE. LINWID: LINLEN ;LENGTH OF LINE (WIDTH). NCMWID: NCMPOS ;POSITION BEYOND WHICH THERE ARE ;NO MORE FIELDS. LINNUM: 0 ;LOCATION TO STORE LINE NUMBER BEFORE BUF ;SO THAT "BLTUC" CAN STORE IT ALL AWAY AT ONCE. 44 ;A COMMA (PRELOAD OR FROM ROM) ;USED BY INPUT STATEMENT SINCE THE ;DATA POINTER ALWAYS STARTS ON A ;COMMA OR TERMINATOR. IFE BUFPAG,< BUF: BLOCK BUFLEN> ;TYPE IN STORED HERE. ;DIRECT STATEMENTS EXECUTE OUT OF ;HERE. REMEMBER "INPUT" SMASHES BUF. ;MUST BE ON PAGE ZERO ;OR ASSIGNMENT OF STRING ;VALUES IN DIRECT STATEMENTS WON'T COPY ;INTO STRING SPACE -- WHICH IT MUST. ;N.B. TWO NONZERO BYTES MUST PRECEDE "BUFLNM".

; --- STORAGE FOR TEMPORARY THINGS ---: TEMPPT: BLOCK 1 ;POINTER AT FIRST FREE TEMP DESCRIPTOR. ;INITIALIZED TO POINT TO TEMPST. LASTPT: BLOCK 2 ;POINTER TO LAST-USED STRING TEMPORARY. TEMPST: BLOCK STRSIZ*NUMTMP ;STORAGE FOR NUMTMP TEMP DESCRIPTORS. INDEX1: BLOCK 2 ;INDEXES. INDEX= INDEX1 INDEX2: BLOCK 2 RESHO: BLOCK 1 ;RESULT OF MULTIPLIER AND DIVIDER. IFN ADDPRC,< RESMOH: BLOCK 1> ;ONE MORE BYTE. RESMO: BLOCK 1 RESLO: BLOCK 1 ADDEND= RESMO ;TEMPORARY USED BY "UMULT". 0 ;OVERFLOW FOR RES.

; --- POINTERS INTO DYNAMIC DATA STRUCTURES ---; TXTTAB: BLOCK 2 ;POINTER TO BEGINNING OF TEXT. ;DOESN'T CHANGE AFTER BEING ;SETUP BY "INIT". VARTAB: BLOCK 2 ;POINTER TO START OF SIMPLE ;VARIABLE SPACE. ;UPDATED WHENEVER THE SIZE OF THE ;PROGRAM CHANGES, SET TO [TXTTAB] ;BY "SCRATCH" ("NEW"). ARYTAB: BLOCK 2 ;POINTER TO BEGINNING OF ARRAY ;TABLE. ;INCREMENTED BY 6 WHENEVER ;A NEW SIMPLE VARIABLE IS FOUND, AND ;SET TO [VARTAB] BY "CLEARC". STREND: BLOCK 2 ;END OF STORAGE IN USE. ;INCREASED WHENEVER A NEW ARRAY ;OR SIMPLE VARIABLE IS ENCOUNTERED. ;SET TO [VARTAB] BY "CLEARC". FRETOP: BLOCK 2 ;TOP OF STRING FREE SPACE. FRESPC: BLOCK 2 ;POINTER TO NEW STRING. MEMSIZ: BLOCK 2 ;HIGHEST LOCATION IN MEMORY.

; --- LINE NUMBERS AND TEXTUAL POINTERS ---: CURLIN: BLOCK 2 ;CURRENT LINE #. ;SET TO 0,255 FOR DIRECT STATEMENTS. OLDLIN: BLOCK 2 ;OLD LINE NUMBER (SETUP BY ^C,"STOP" ;OR "END" IN A PROGRAM). POKER= LINNUM ;SET UP LOCATION USED BY POKE. ;TEMPORARY FOR INPUT AND READ CODE OLDTXT: BLOCK 2 ;OLD TEXT POINTER. ;POINTS AT STATEMENT TO BE EXEC'D NEXT. DATLIN: BLOCK 2 ;DATA LINE # -- REMEMBER FOR ERRORS. DATPTR: BLOCK 2 ;POINTER TO DATA. INITIALIZED TO POINT ;AT THE ZERO IN FRONT OF [TXTTAB] ;BY "RESTORE" WHICH IS CALLED BY "CLEARC". ;UPDATED BY EXECUTION OF A "READ". INPPTR: BLOCK 2 ;THIS REMEMBERS WHERE INPUT IS COMING FROM.

; --- STUFF USED IN EVALUATIONS ---: VARNAM: BLOCK 2 ;VARIABLE'S NAME IS STORED HERE. VARPNT: BLOCK 2 ;POINTER TO VARIABLE IN MEMORY. FDECPT= VARPNT ;POINTER INTO POWER OF TENS OF "FOUT". FORPNT: BLOCK 2 ;A VARIABLE'S POINTER FOR "FOR" LOOPS ;AND "LET" STATEMENTS. LSTPNT= FORPNT ;PNTR TO LIST STRING. ANDMSK= FORPNT ;THE MASK USED BY WAIT FOR ANDING. EORMSK= FORPNT+1 ;THE MASK FOR EORING IN WAIT. OPPTR: BLOCK 2 ;POINTER TO CURRENT OP'S ENTRY IN "OPTAB". VARTXT= OPPTR ;POINTER INTO LIST OF VARIABLES. OPMASK: BLOCK 1 ;MASK CREATED BY CURRENT OPERATOR. DOMASK=TANSGN ;MASK IN USE BY RELATION OPERATIONS. DEFPNT: BLOCK 2 ;POINTER USED IN FUNCTION DEFINITION. GRBPNT= DEFPNT ;ANOTHER USED IN GARBAGE COLLECTION. DSCPNT: BLOCK 2 ;POINTER TO A STRING DESCRIPTOR. IFN ADDPRC,<BLOCK 1> ;FOR TEMPF3. FOUR6: EXP STRSIZ ;VARIABLE CONSTANT USED BY GARB COLLECT.

; --- ET CETERA ---: JMPER: JMP 60000 SIZE= JMPER+1 OLDOV= JMPER+2 ;THE OLD OVERFLOW. TEMPF3= DEFPNT ;A THIRD FAC TEMPORARY (4 BYTES). TEMPF1: IFN ADDPRC,<0> ;FOR TEMPF1S EXTRA BYTE. HIGHDS: BLOCK 2 ;DESINATION OF HIGHEST ELEMENT IN BLT. HIGHTR: BLOCK 2 ;SOURCE OF HIGHEST ELEMENT TO MOVE. TEMPF2: IFN ADDPRC,<0> ;FOR TEMPF2S EXTRA BYTE. LOWDS: BLOCK 2 ;LOCATION OF LAST BYTE TRANSFERRED INTO. LOWTR: BLOCK 2 ;LAST THING TO MOVE IN BLT. ARYPNT= HIGHDS ;A POINTER USED IN ARRAY BUILDING. GRBTOP= LOWTR ;A POINTER USED IN GARBAGE COLLECTION. DECCNT= LOWDS ;NUMBER OF PLACES BEFORE DECIMAL POINT. TENEXP= LOWDS+1 ;HAS A DPT BEEN INPUT? DPTFLG= LOWTR ;BASE TEN EXPONENT. EXPSGN= LOWTR+1 ;SIGN OF BASE TEN EXPONENT.

; --- THE FLOATING ACCUMULATOR ---: FAC: FACEXP: 0 FACHO: 0 ;MOST SIGNIFICANT BYTE OF MANTISSA. IFN ADDPRC,< FACMOH: 0> ;ONE MORE. FACMO: 0 ;MIDDLE ORDER OF MANTISSA. FACLO: 0 ;LEAST SIG BYTE OF MANTISSA. FACSGN: 0 ;SIGN OF FAC (0 OR -1) WHEN UNPACKED. SGNFLG: 0 ;SIGN OF FAC IS PRESERVED BERE BY "FIN". DEGREE= SGNFLG ;A COUNT USED BY POLYNOMIALS. DSCTMP= FAC ;THIS IS WHERE TEMP DESCS ARE BUILT. INDICE= FACMO ;INDICE IS SET UP HERE BY "QINT". BITS: 0 ;SOMETHING FOR "SHIFTR" TO USE.

; --- THE FLOATING ARGUMENT (UNPACKED) ---: ARGEXP: 0 ARGHO: 0 IFN ADDPRC,<ARGMOH: 0> ARGMO: 0 ARGLO: 0 ARGSGN: 0

ARISGN: 0 ;A SIGN REFLECTING THE RESULT. FACOV: 0 ;OVERFLOW BYTE OF THE FAC. STRNG1= ARISGN ;POINTER TO A STRING OR DESCRIPTOR.

FBUFPT: BLOCK 2 ;POINTER INTO FBUFFR USED BY FOUT. BUFPTR= FBUFPT ;POINTER TO BUF USED BY "CRUNCH". STRNG2= FBUFPT ;POINTER TO STRING OR DESC. POLYPT= FBUFPT ;POINTER INTO POLYNOMIAL COEFFICIENTS. CURTOL= FBUFPT ;ABSOLUTE LINEAR INDEX IS FORMED HERE. PAGE SUBTTL RAM CODE. ; THIS CODE GETS CHANGED THROUGHOUT EXECUTION. ; IT IS MADE TO BE FAST THIS WAY. ; ALSO, [X] AND [Y] ARE NOT DISTURBED ; ; "CHRGET" USING [TXTPTR] AS THE CURRENT TEXT PNTR ; FETCHES A NEW CHARACTER INTO ACCA AFTER INCREMENTING [TXTPTR] ; AND SETS CONDITION CODES ACCORDING TO WHAT'S IN ACCA. ; NOT C= NUMERIC ("0" THRU "9") ; Z= ":" OR END-OF-LINE (A NULL) ; ; [ACCA] = NEW CHAR. ; [TXTPTR]=[TXTPTR]+1 ; ; THE FOLLOWING EXISTS IN ROM IF ROM EXISTS AND IS LOADED ; DOWN HERE BY INIT. OTHERWISE IT IS JUST LOADED INTO THIS ; RAM LIKE ALL THE REST OF RAM IS LOADED. ; CHRGET: INC CHRGET+7 ;INCREMENT THE WHOLE TXTPTR. BNE CHRGOT INC CHRGET+8 CHRGOT: LDA 60000 ;A LOAD WITH AN EXT ADDR. TXTPTR= CHRGOT+1 CMPI " " ;SKIP SPACES. BEQ CHRGET QNUM: CMPI ":" ;IS IT A ":"? BCS CHRRTS ;IT IS .GE. ":" SEC SBCI "0" ;ALL CHARS .GT. "9" HAVE RET'D SO SEC SBCI 256-"0" ;SEE IF NUMERIC. ;TURN CARRY ON IF NUMERIC. ;ALSO, SETZ IF NULL. CHRRTS: RTS ;RETURN TO CALLER.

RNDX: 128 ;LOADED OR FROM ROM. 79 ;THE INITIAL RANDOM NUMBER. 199 82 IFN ADDPRC,<89> ;ONE MORE BYTE.

ORG 255 ;PAGE 1 STUFF COMING UP. LOFBUF: BLOCK 1 ;THE LOW FAC BUFFER. COPYABLE. ;--- PAGE ZERO/ONE BOUNDARY ---. ;MUST HAVE 13 CONTIGUOUS BYTES. FBUFFR: BLOCK 3*ADDPRC+13 ;BUFFER FOR "FOUT". ;ON PAGE 1 SO THAT STRING IS NOT COPIED.

;STACK IS LOCATED HERE. IE FROM THE END OF FBUFFR TO STKEND. PAGE SUBTTL DISPATCH TABLES, RESERVED WORDS, AND ERROR TEXTS.

ORG ROMLOC

STMDSP: ADR(END-1) ADR(FOR-1) ADR(NEXT-1) ADR(DATA-1) IFN EXTIO,< ADR(INPUTN-1)> ADR(INPUT-1) ADR(DIM-1) ADR(READ-1) ADR(LET-1) ADR(GOTO-1) ADR(RUN-1) ADR(IF-1) ADR(RESTORE-1) ADR(GOSUB-1) ADR(RETURN-1) ADR(REM-1) ADR(STOP-1) ADR(ONGOTO-1) IFN NULCMD,< ADR(NULL-1)> ADR(FNWAIT-1) IFN DISKO,< IFE REALIO-3,< ADR(CQLOAD-1) ADR(CQSAVE-1) ADR(CQVERF-1)> IFN REALIO,< IFN REALIO-2,< IFN REALIO-3,< IFN REALIO-5,< ADR(LOAD-1) ADR(SAVE-1)>>>> IFN REALIO-1,< IFN REALIO-3,< IFN REALIO-4,< ADR(511) ;ADDRESS OF LOAD ADR(511)>>>> ;ADDRESS OF SAVE ADR(DEF-1) ADR(POKE-1) IFN EXTIO,< ADR(PRINTN-1)> ADR(PRINT-1) ADR(CONT-1) IFE REALIO,< ADR(DDT-1)> ADR(LIST-1) ADR(CLEAR-1) IFN EXTIO,< ADR(CMD-1) ADR(CQSYS-1) ADR(CQOPEN-1) ADR(CQCLOS-1)> IFN GETCMD,< ADR(GET-1)> ;FILL W/ GET ADDR. ADR(SCRATH-1)

FUNDSP: ADR(SGN) ADR(INT) ADR(ABS) IFE ROMSW,< USRLOC: ADR(FCERR)> ;INITIALLY NO USER ROUTINE. IFN ROMSW,< USRLOC: ADR(USRPOK)> ADR(FRE) ADR(POS) ADR(SQR) ADR(RND) ADR(LOG) ADR(EXP) IFN KIMROM,< REPEAT 4,< ADR(FCERR)>> IFE KIMROM,< COSFIX: ADR(COS) SINFIX: ADR(SIN) TANFIX: ADR(TAN) ATNFIX: ADR(ATN)> ADR(PEEK) ADR(LEN) ADR(STR) ADR(VAL) ADR(ASC) ADR(CHR) ADR(LEFT) ADR(RIGHT) ADR(MID) OPTAB: 121 ADR(FADDT-1) 121 ADR(FSUBT-1) 123 ADR(FMULTT-1) 123 ADR(FDIVT-1) 127 ADR(FPWRT-1) 80 ADR(ANDOP-1) 70 ADR(OROP-1) NEGTAB: 125 ADR(NEGOP-1) NOTTAB: 90 ADR(NOTOP-1) PTDORL: 100 ;PRECEDENCE. ADR (DOREL-1) ;OPERATOR ADDRESS. ; ; TOKENS FOR RESERVED WORDS ALWAYS HAVE THE MOST ; SIGNIFICANT BIT ON. ; THE LIST OF RESERVED WORDS: ; Q=128-1 DEFINE DCI(A),<Q=Q+1 DC(A)> RESLST: DCI"END" ENDTK==Q DCI"FOR" FORTK==Q DCI"NEXT" DCI"DATA" DATATK==Q IFN EXTIO,< DCI"INPUT#"> DCI"INPUT" DCI"DIM" DCI"READ" DCI"LET" DCI"GOTO" GOTOTK==Q DCI"RUN" DCI"IF" DCI"RESTORE" DCI"GOSUB" GOSUTK=Q DCI"RETURN" DCI"REM" REMTK=Q DCI"STOP" DCI"ON" IFN NULCMD,< DCI"NULL"> DCI"WAIT" IFN DISKO,< DCI"LOAD" DCI"SAVE" IFE REALIO-3,< DCI"VERIFY">> DCI"DEF" DCI"POKE" IFN EXTIO,< DCI"PRINT#"> DCI"PRINT" PRINTK==Q DCI"CONT" IFE REALIO,< DCI"DDT"> DCI"LIST" IFN REALIO-3,< DCI"CLEAR"> IFE REALIO-3,< DCI"CLR"> IFN EXTIO,< DCI"CMD" DCI"SYS" DCI"OPEN" DCI"CLOSE"> IFN GETCMD,< DCI"GET"> DCI"NEW" SCRATK=Q ; END OF COMMAND LIST. "T" "A" "B" "("+128 Q=Q+1 TABTK=Q DCI"TO" TOTK==Q DCI"FN" FNTK==Q "S" "P" "C" "("+128 ;MACRO DOESNT LIKE ('S IN ARGUMENTS. Q=Q+1 SPCTK==Q DCI"THEN" THENTK=Q DCI"NOT" NOTTK==Q DCI"STEP" STEPTK=Q DCI"+" PLUSTK=Q DCI"-" MINUTK=Q DCI"*" DCI"/" DCI"^" DCI"AND" DCI"OR" 190 ;A GREATER THAN SIGN Q=Q+1 GREATK=Q DCI"=" EQULTK=Q 188 Q=Q+1 ;A LESS THAN SIGN LESSTK=Q ; ; NOTE DANGER OF ONE RESERVED WORD BEING A PART ; OF ANOTHER: ; IE . . IF 2 GREATER THAN F OR T=5 THEN... ; WILL NOT WORK!!! SINCE "FOR" WILL BE CRUNCHED!! ; IN ANY CASE MAKE SURE THE SMALLER WORD APPEARS ; SECOND IN THE RESERVED WORD TABLE ("INP" AND "INPUT") ; ANOTHER EXAMPLE: IF T OR Q THEN ... "TO" IS CRUNCHED ; DCI"SGN" ONEFUN=Q DCI"INT" DCI"ABS" DCI"USR" DCI"FRE" DCI"POS" DCI"SQR" DCI"RND" DCI"LOG" DCI"EXP" DCI"COS" DCI"SIN" DCI"TAN" DCI"ATN" DCI"PEEK" DCI"LEN" DCI"STR$" DCI"VAL" DCI"ASC" DCI"CHR$" LASNUM==Q ;NUMBER OF LAST FUNCTION ;THAT TAKES ONE ARG DCI"LEFT$" DCI"RIGHT$" DCI"MID$" DCI"GO" GOTK==Q 0 ;MARKS END OF RESERVED WORD LIST

IFE LNGERR,< Q=0-2 DEFINE DCE(X),<Q=Q+2 DC(X)> ERRTAB: DCE"NF" ERRNF==Q ;NEXT WITHOUT FOR. DCE"SN" ERRSN==Q ;SYNTAX DCE"RG" ERRRG==Q ;RETURN WITHOUT GOSUB. DCE"OD" ERROD==Q ;OUT OF DATA. DCE"FC" ERRFC==Q ;ILLEGAL QUANTITY. DCE"OV" ERROV==Q ;OVERFLOW. DCE"OM" ERROM==Q ;OUT OF MEMORY. DCE"US" ERRUS==Q ;UNDEFINED STATEMENT. DCE"BS" ERRBS==Q ;BAD SUBSCRIPT. DCE"DD" ERRDD==Q ;REDIMENSIONED ARRAY. DCE"/0" ERRDV0==Q ;DIVISION BY ZERO. DCE"ID" ERRID==Q ;ILLEGAL DIRECT. DCE"TM" ERRTM==Q ;TYPE MISMATCH. DCE"LS" ERRLS==Q ;STRING TOO LONG. IFN EXTIO,< DCE"FD" ;FILE DATA. ERRBD==Q> DCE"ST" ERRST==Q ;STRING FORMULA TOO COMPLEX. DCE"CN" ERRCN==Q ;CAN'T CONTINUE. DCE"UF" ERRUF==Q> ;UNDEFINED FUNCTION.

IFN LNGERR,< Q=0 ; NOTE: THIS ERROR COUNT TECHNIQUE WILL NOT WORK IF THERE ARE MORE ; THAN 256 CHARACTERS OF ERROR MESSAGES ERRTAB: DC"NEXT WITHOUT FOR" ERRNF==Q Q=Q+16 DC"SYNTAX" ERRSN==Q Q=Q+6 DC"RETURN WITHOUT GOSUB" ERRRG==Q Q=Q+20 DC"OUT OF DATA" ERROD==Q Q=Q+11 DC"ILLEGAL QUANTITY" ERRFC==Q Q=Q+16 DC"OVERFLOW" ERROV==Q Q=Q+8 DC"OUT OF MEMORY" ERROM==Q Q=Q+13 DC"UNDEF'D STATEMENT" ERRUS==Q Q=Q+17 DC"BAD SUBSCRIPT" ERRBS==Q Q=Q+13 DC"REDIM'D ARRAY" ERRDD==Q Q=Q+13 DC"DIVISION BY ZERO" ERRDV0==Q Q=Q+16 DC"ILLEGAL DIRECT" ERRID==Q Q=Q+14 DC"TYPE MISMATCH" ERRTM==Q Q=Q+13 DC"STRING TOO LONG" ERRLS==Q Q=Q+15 IFN EXTIO,< DC"FILE DATA" ERRBD==Q Q=Q+9> DC"FORMULA TOO COMPLEX" ERRST==Q Q=Q+19 DC"CAN'T CONTINUE" ERRCN==Q Q=Q+14 DC"UNDEF'D FUNCTION" ERRUF==Q>

; ; NEEDED FOR MESSAGES IN ALL VERSIONS. ; ERR: DT" ERROR" 0 INTXT: DT" IN " 0 REDDY: ACRLF IFE REALIO-3,< DT"READY."> IFN REALIO-3,< DT"OK"> ACRLF 0 BRKTXT: ACRLF DT"BREAK" 0 PAGE SUBTTL GENERAL STORAGE MANAGEMENT ROUTINES. ; ; FIND A "FOR" ENTRY ON THE STACK VIA "VARPNT". ; FORSIZ==2*ADDPRC+16 FNDFOR: TSX ;LOAD XREG WITH STK PNTR. REPEAT 4,<INX> ;IGNORE ADR(NEWSTT) AND RTS ADDR. FFLOOP: LDA 257,X ;GET STACK ENTRY. CMPI FORTK ;IS IT A "FOR" TOKEN? BNE FFRTS ;NO, NO "FOR" LOOPS WITH THIS PNTR. LDA FORPNT+1 ;GET HIGH. BNE CMPFOR LDA 258,X ;PNTR IS ZERO, SO ASSUME THIS ONE. STA FORPNT LDA 259,X STA FORPNT+1 CMPFOR: CMP 259,X BNE ADDFRS ;NOT THIS ONE. LDA FORPNT ;GET DOWN. CMP 258,X BEQ FFRTS ;WE GOT IT! WE GOT IT! ADDFRS: TXA CLC ;ADD 16 TO X. ADCI FORSIZ TAX ;RESULT BACK INTO X. BNE FFLOOP FFRTS: RTS ;RETURN TO CALLER.

; ; THIS IS THE BLOCK TRANSFER ROUTINE. ; IT MAKES SPACE BY SHOVING EVERYTHING FORWARD. ; ; ON ENTRY: ; [Y,A]=[HIGHDS] (FOR REASON). ; [HIGHDS]= DESTINATION OF [HIGH ADDRESS]. ; [LOWTR]= LOWEST ADDR TO BE TRANSFERRED. ; [HIGHTR]= HIGHEST ADDR TO BE TRANSFERRED. ; ; A CHECK IS MADE TO ASCERTAIN THAT A REASONABLE ; AMOUNT OF SPACE REMAINS BETWEEN THE BOTTOM ; OF THE STRINGS AND THE HIGHEST LOCATION TRANSFERRED INTO. ; ; ON EXIT: ; [LOWTR] ARE UNCHANGED. ; [HIGHTR]=[LOWTR]-200 OCTAL. ; [HIGHDS]=LOWEST ADDR TRANSFERRED INTO MINUS 200 OCTAL. ; BLTU: JSR REASON ;ASCERTAIN THAT STRING SPACE WON'T ;BE OVERRUN. STWD STREND BLTUC: SEC ;PREPARE TO SUBTRACT. LDA HIGHTR SBC LOWTR ;COMPUTE NUMBER OF THINGS TO MOVE. STA INDEX ;SAVE FOR LATER. TAY LDA HIGHTR+1 SBC LOWTR+1 TAX ;PUT IT IN A COUNTER REGISTER. INX ;SO THAT COUNTER ALGORITHM WORKS. TYA ;SEE IF LOW PART OF COUNT IS ZERO. BEQ DECBLT ;YES, GO START MOVING BLOCKS. LDA HIGHTR ;NO, MUST MODIFY BASE ADDR. SEC SBC INDEX ;BORROW IS OFF SINCE [HIGHTR].GT.[LOWTR]. STA HIGHTR ;SAVE MODIFIED BASE ADDR. BCS BLT1 ;IF NO BORROW, GO SHOVE IT. DEC HIGHTR+1 ;BORROW IMPLIES SUB 1 FROM HIGH ORDER. SEC BLT1: LDA HIGHDS ;MOD BASE OF DEST ADDR. SBC INDEX STA HIGHDS BCS MOREN1 ;NO BORROW. DEC HIGHDS+1 ;DECREMENT HIGH ORDER BYTE. BCC MOREN1 ;ALWAYS SKIP. BLTLP: LDADY HIGHTR ;FETCH BYTE TO MOVE STADY HIGHDS ;MOVE IT IN, MOVE IT OUT. MOREN1: DEY BNE BLTLP LDADY HIGHTR ;MOVE LAST OF THE BLOCK. STADY HIGHDS DECBLT: DEC HIGHTR+1 DEC HIGHDS+1 ;START ON NEW BLOCKS. DEX BNE MOREN1 RTS ;RETURN TO CALLER.

; ; THIS ROUTINE IS USED TO ASCERTAIN THAT A GIVEN ; NUMBER OF LOCS REMAIN AVAILABLE FOR THE STACK. ; THE CALL IS: ; LDAI NUMBER OF 2-BYTE ENTRIES NEEDED. ; JSR GETSTK ; ; THIS ROUTINE MUST BE CALLED BY ANY ROUTINE WHICH PUTS ; AN ARBITRARY AMOUNT OF STUFF ON THE STACK, ; I.E., ANY RECURSIVE ROUTINE LIKE "FRMEVL". ; IT IS ALSO CALLED BY ROUTINES SUCH AS "GOSUB" AND "FOR" ; WHICH MAKE PERMANENT ENTRIES ON THE STACK. ; ; ROUTINES WHICH MERELY USE AND FREE UP THE GUARANTEED ; NUMLEV LOCATIONS NEED NOT CALL THIS. ; ; ; ON EXIT: ; [A] AND [X] HAVE BEEN MODIFIED. ; GETSTK: ASL A, ;MULT [A] BY 2. NB, CLEARS C BIT. ADCI 2NUMLEV+<3ADDPRC>+13 ;MAKE SURE 2*NUMLEV+13 LOCS ;(13 BECAUSE OF FBUFFR) BCS OMERR ;WILL REMAIN IN STACK. STA INDEX TSX ;GET STACKED. CPX INDEX ;COMPARE. BCC OMERR ;IF STACK.LE.INDEX1, OM. RTS

; ; [Y,A] IS A CERTAIN ADDRESS. "REASON" MAKES SURE ; IT IS LESS THAN [FRETOP]. ; REASON: CPY FRETOP+1 BCC REARTS BNE TRYMOR ;GO GARB COLLECT. CMP FRETOP BCC REARTS TRYMOR: PHA LDXI 8+ADDPRC ;IF TEMPF2 HAS ZERO IN BETWEEN. TYA REASAV: PHA LDA HIGHDS-1,X ;SAVE HIGHDS ON STACK. DEX BPL REASAV ;PUT 8 OF THEM ON STK. JSR GARBA2 ;GO GARB COLLECT. LDXI 256-8-ADDPRC REASTO: PLA STA HIGHDS+8+ADDPRC,X ;RESTORE AFTER GARB COLLECT. INX BMI REASTO PLA TAY PLA ;RESTORE A AND Y. CPY FRETOP+1 ;COMPARE HIGHS BCC REARTS BNE OMERR ;HIGHER IS BAD. CMP FRETOP ;AND THE LOWS. BCS OMERR REARTS: RTS

PAGE SUBTTL ERROR HANDLER, READY, TERMINAL INPUT, COMPACTIFY, NEW, REINIT. OMERR: LDXI ERROM ERROR: IFN REALIO,< LSR CNTWFL> ;FORCE OUTPUT. IFN EXTIO,< LDA CHANNL ;CLOSE NON-TERMINAL CHANNEL. BEQ ERRCRD JSR CQCCHN ;CLOSE IT. LDAI 0 STA CHANNL> ERRCRD: JSR CRDO ;OUTPUT CRLF. JSR OUTQST ;PRINT A QUESTION MARK IFE LNGERR,< LDA ERRTAB,X, ;GET FIRST CHR OF ERR MSG. JSR OUTDO ;OUTPUT IT. LDA ERRTAB+1,X, ;GET SECOND CHR. JSR OUTDO> ;OUTPUT IT. IFN LNGERR,< GETERR: LDA ERRTAB,X PHA ANDI 127 ;GET RID OF HIGH BIT. JSR OUTDO ;OUTPUT IT. INX PLA ;LAST CHAR OF MESSAGE? BPL GETERR> ;NO. GO GET NEXT AND OUTPUT IT. TYPERR: JSR STKINI ;RESET THE STACK AND FLAGS. LDWDI ERR ;GET PNTR TO " ERROR". ERRFIN: JSR STROUT ;OUTPUT IT. LDY CURLIN+1 INY ;WAS NUMBER 64000? BEQ READY ;YES, DON'T TYPE LINE NUMBER. JSR INPRT READY: IFN REALIO,< LSR CNTWFL> ;TURN OUTPUT BACK ON IF SUPRESSED LDWDI REDDY ;SAY "OK". IFN REALIO-3,< JSR RDYJSR> ;OR GO TO INIT IF INIT ERROR. IFE REALIO-3,< JSR STROUT> ;NO INIT ERRORS POSSIBLE. MAIN: JSR INLIN ;GET A LINE FROM TERMINAL. STXY TXTPTR JSR CHRGET TAX ;SET ZERO FLAG BASED ON [A] ;THIS DISTINGUISHES ":" AND 0 BEQ MAIN ;IF BLANK LINE, GET ANOTHER. LDXI 255 ;SET DIRECT LINE NUMBER. STX CURLIN+1 BCC MAIN1 ;IS A LINE NUMBER. NOT DIRECT. JSR CRUNCH ;COMPACTIFY. JMP GONE ;EXECUTE IT. MAIN1: JSR LINGET ;READ LINE NUMBER INTO "LINNUM". JSR CRUNCH STY COUNT ;RETAIN CHARACTER COUNT. JSR FNDLIN BCC NODEL ;NO MATCH, SO DON'T DELETE. LDYI 1 LDADY LOWTR STA INDEX1+1 LDA VARTAB STA INDEX1 LDA LOWTR+1 ;SET TRANSFER TO. STA INDEX2+1 LDA LOWTR DEY SBCDY LOWTR ;COMPUTE NEGATIVE LENGTH. CLC ADC VARTAB ;COMPUTE NEW VARTAB. STA VARTAB STA INDEX2 ;SET LOW OF TRANS TO. LDA VARTAB+1 ADCI 255 STA VARTAB+1 ;COMPUTE HIGH OF VARTAB. SBC LOWTR+1 ;COMPUTE NUMBER OF BLOCKS TO MOVE. TAX SEC LDA LOWTR SBC VARTAB ;COMPUTE OFFSET. TAY BCS QDECT1 ;IF VARTAB.LE.LOWTR, INX ;DECR DUE TO CARRY, AND DEC INDEX2+1 ;DECREMENT STORE SO CARRY WORKS. QDECT1: CLC ADC INDEX1 BCC MLOOP DEC INDEX1+1 CLC ;FOR LATER ADCQ MLOOP: LDADY INDEX1 STADY INDEX2 INY BNE MLOOP ;BLOCK DONE? INC INDEX1+1 INC INDEX2+1 DEX BNE MLOOP ;DO ANOTHER BLOCK. ALWAYS. NODEL: JSR RUNC ;RESET ALL VARIABLE INFO SO GARBAGE ;COLLECTION CAUSED BY REASON WILL WORK JSR LNKPRG ;FIX UP THE LINKS LDA BUF ;SEE IF ANYTHNG THERE BEQ MAIN CLC LDA VARTAB STA HIGHTR ;SETUP HIGHTR. ADC COUNT ;ADD LENGTH OF LINE TO INSERT. STA HIGHDS ;THIS GIVES DEST ADDR. LDY VARTAB+1 STY HIGHTR+1 ;SAME FOR HIGH ORDERS. BCC NODELC INY NODELC: STY HIGHDS+1 JSR BLTU IFN BUFPAG,< LDWD LINNUM ;POSITION THE BINARY LINE NUMBER STWD BUF-2> ;IN FRONT OF BUF LDWD STREND STWD VARTAB LDY COUNT DEY STOLOP: LDA BUF-4,Y STADY LOWTR DEY BPL STOLOP FINI: JSR RUNC ;DO CLEAR & SET UP STACK. ;AND SET [TXTPTR] TO [TXTTAB]-1. JSR LNKPRG ;FIX UP PROGRAM LINKS JMP MAIN LNKPRG: LDWD TXTTAB ;SET [INDEX] TO [TXTTAB]. STWD INDEX CLC ; ; CHEAD GOES THROUGH PROGRAM STORAGE AND FIXES ; UP ALL THE LINKS. THE END OF EACH LINE IS FOUND ; BY SEARCHING FOR THE ZERO AT THE END. ; THE DOUBLE ZERO LINK IS USED TO DETECT THE END OF THE PROGRAM. ; CHEAD: LDYI 1 LDADY INDEX ;ARRIVED AT DOUBLE ZEROES? BEQ LNKRTS LDYI 4 CZLOOP: INY ;THERE IS AT LEAST ONE BYTE. LDADY INDEX BNE CZLOOP ;NO, CONTINUE SEARCHING. INY ;GO ONE BEYOND. TYA ADC INDEX TAX LDYI 0 STADY INDEX LDA INDEX+1 ADCI 0 INY STADY INDEX STX INDEX STA INDEX+1 BCCA CHEAD ;ALWAYS BRANCHES. LNKRTS: RTS ; ; THIS IS THE LINE INPUT ROUTINE. ; IT READS CHARACTERS INTO BUF USING BACKARROW (UNDERSCORE, OR ; SHIFT O) AS THE DELETE CHARACTER AND @ AS THE ; LINE DELETE CHARACTER. IF MORE THAN BUFLEN CHARACTERS ; ARE TYPED, NO ECHOING IS DONE UNTIL A BACKARROW OR @ OR CR ; IS TYPED. CONTROL-G WILL BE TYPED FOR EACH EXTRA CHARACTER. ; THE ROUTINE IS ENTERED AT INLIN. ; IFE REALIO-4,< INLIN: LDXI 128 ;NO PROMPT CHARACTER STX CQPRMP JSR CQINLN ;GET A LINE ONTO PAGE 2 CPXI BUFLEN-1 BCS GDBUFS ;NOT TOO MANY CHARACTERS LDXI BUFLEN-1 GDBUFS: LDAI 0 ;PUT A ZERO AT THE END STA BUF,X TXA BEQ NOCHR LOPBHT: LDA BUF-1,X ANDI 127 STA BUF-1,X DEX BNE LOPBHT NOCHR: LDAI 0 LDXYI <BUF-1> ;POINT AT THE BEGINNING RTS> IFN REALIO-4,< IFN REALIO-3,< LINLIN: IFE REALIO-2,< JSR OUTDO> ;ECHO IT. DEX ;BACKARROW SO BACKUP PNTR AND BPL INLINC ;GET ANOTHER IF COUNT IS POSITIVE. INLINN: IFE REALIO-2,< JSR OUTDO> ;PRINT THE @ OR A SECOND BACKARROW ;IF THERE WERE TOO MANY. JSR CRDO> INLIN: LDXI 0 INLINC: JSR INCHR ;GET A CHARACTER. IFN REALIO-3,< CMPI 7 ;IS IT BOB ALBRECHT RINGING THE BELL ;FOR SCHOOL KIDS? BEQ GOODCH> CMPI 13 ;CARRIAGE RETURN? BEQ FININ1 ;YES, FINISH UP. IFN REALIO-3,< CMPI 32 ;CHECK FOR FUNNY CHARACTERS. BCC INLINC CMPI 125 ;IS IT TILDA OR DELETE? BCS INLINC ;BIG BAD ONES TOO. CMPI "@" ;LINE DELETE? BEQ INLINN ;YES. CMPI "_" ;CHARACTER DELETE? BEQ LINLIN> ;YES. GOODCH: IFN REALIO-3,< CPXI BUFLEN-1 ;LEAVE ROOM FOR NULL. ;COMMO ASSURES US NEVER MORE THAN BUFLEN. BCS OUTBEL> STA BUF,X INX IFE REALIO-2,<SKIP2> IFN REALIO-2,<BNE INLINC> IFN REALIO-3,< OUTBEL: LDAI 7 IFN REALIO,< JSR OUTDO> ;ECHO IT. BNE INLINC> ;CYCLE ALWAYS. FININ1: JMP FININL> ;GO TO FININL FAR, FAR AWAY. INCHR:
IFE REALIO-3,< JSR CQINCH> ;FOR COMMODORE. IFE REALIO-2,< INCHRL: LDA ^O176000 REPEAT 4,<NOP> LSR A, BCC INCHRL LDA ^O176001 ;GET THE CHARACTER. REPEAT 4,<NOP> ANDI 127> IFE REALIO-1,< JSR ^O17132> ;1E5A FOR MOS TECH. IFE REALIO-4,< JSR CQINCH ;FD0C FOR APPLE COMPUTER. ANDI 127> IFE REALIO,< TJSR INSIM##> ;GET A CHARACTER FROM SIMULATOR

IFN REALIO,< IFN EXTIO,< LDY CHANNL ;CNT-O HAS NO EFFECT IF NOT FROM TERM. BNE INCRTS> CMPI CONTW ;SUPPRESS OUTPUT CHARACTER (^W). BNE INCRTS ;NO, RETURN. PHA COM CNTWFL ;COMPLEMENT ITS STATE. PLA> INCRTS: RTS ;END OF INCHR.

; ; ALL "RESERVED" WORDS ARE TRANSLATED INTO SINGLE ; BYTES WITH THE MSB ON. THIS SAVES SPACE AND TIME ; BY ALLOWING FOR TABLE DISPATCH DURING EXECUTION. ; THEREFORE ALL STATEMENTS APPEAR TOGETHER IN THE ; RESERVED WORD LIST IN THE SAME ORDER THEY ; APPEAR IN STMDSP. ; BUFOFS=0 ;THE AMOUNT TO OFFSET THE LOW BYTE ;OF THE TEXT POINTER TO GET TO BUF ;AFTER TXTPTR HAS BEEN SETUP TO POINT INTO BUF IFN BUFPAG,< BUFOFS=<BUF/256>*256> CRUNCH: LDX TXTPTR ;SET SOURCE POINTER. LDYI 4 ;SET DESTINATION OFFSET. STY DORES ;ALLOW CRUNCHING. KLOOP: LDA BUFOFS,X IFE REALIO-3,< BPL CMPSPC ;GO LOOK AT SPACES. CMPI PI ;PI?? BEQ STUFFH ;GO SAVE IT. INX ;SKIP NO PRINTING. BNE KLOOP> ;ALWAYS GOES. CMPSPC: CMPI " " ;IS IT A SPACE TO SAVE? BEQ STUFFH ;YES, GO SAVE IT. STA ENDCHR ;IF IT'S A QUOTE, THIS WILL ;STOP LOOP WHEN OTHER QUOTE APPEARS. CMPI 34 ;QUOTE SIGN? BEQ STRNG ;YES, DO SPECIAL STRING HANDLING. BIT DORES ;TEST FLAG. BVS STUFFH ;NO CRUNCH, JUST STORE. CMPI "?" ;A QMARK? BNE KLOOP1 LDAI PRINTK ;YES, STUFF A "PRINT" TOKEN. BNE STUFFH ;ALWAYS GO TO STUFFH. KLOOP1: CMPI "0" ;SKIP NUMERICS. BCC MUSTCR CMPI 60 ;":" AND ";" ARE ENTERED STRAIGHTAWAY. BCC STUFFH MUSTCR: STY BUFPTR ;SAVE BUFFER POINTER. LDYI 0 ;LOAD RESLST POINTER. STY COUNT ;ALSO CLEAR COUNT. DEY STX TXTPTR ;SAVE TEXT POINTER FOR LATER USE. DEX RESER: INY RESPUL: INX RESCON: LDA BUFOFS,X SEC ;PREPARE TO SUBSTARCT. SBC RESLST,Y ;CHARACTERS EQUAL? BEQ RESER ;YES, CONTINUE SEARCH. CMPI 128 ;NO BUT MAYBE THE END IS HERE. BNE NTHIS ;NO, TRULY UNEQUAL. ORA COUNT GETBPT: LDY BUFPTR ;GET BUFFER PNTR. STUFFH: INX INY STA BUF-5,Y LDA BUF-5,Y BEQ CRDONE ;NULL IMPLIES END OF LINE. SEC ;PREPARE TO SUBSTARCT. SBCI ":" ;IS IT A ":"? BEQ COLIS ;YES, ALLOW CRUNCHING AGAIN. CMPI DATATK-":" ;IS IT A DATATK? BNE NODATT ;NO, SEE IF IT IS REM TOKEN. COLIS: STA DORES ;SETUP FLAG. NODATT: SEC ;PREP TO SBCQ SBCI REMTK-":" ;REM ONLY STOPS ON NULL. BNE KLOOP ;NO, CONTINUE CRUNCHING. STA ENDCHR ;REM STOPS ONLY ON NULL, NOT : OR ". STR1: LDA BUFOFS,X BEQ STUFFH ;YES, END OF LINE, SO DONE. CMP ENDCHR ;END OF GOBBLE? BEQ STUFFH ;YES, DONE WITH STRING. STRNG: INY ;INCREMENT BUFFER POINTER. STA BUF-5,Y INX BNE STR1 ;PROCESS NEXT CHARACTER. NTHIS: LDX TXTPTR ;RESTORE TEXT POINTER. INC COUNT ;INCREMENT RES WORD COUNT. NTHIS1: INY LDA RESLST-1,Y, ;GET RES CHARACTER. BPL NTHIS1 ;END OF ENTRY? LDA RESLST,Y, ;YES. IS IT THE END? BNE RESCON ;NO, TRY THE NEXT WORD. LDA BUFOFS,X ;YES, END OF TABLE. GET 1ST CHR. BPL GETBPT ;STORE IT A