青春时代是一个短暂的美梦,当你醒来时,它早已消失得无影无踪了。
 
昨日:篇  今日:篇   总帖:篇   会员:
admin
夜月琉璃Lv21   
比尔·盖茨写的最古老程序曝光:BAT程序员膜拜     

比尔·盖茨31岁,就成为世界首富。很多人好奇,作为世界第一大PC系统的创始人,抛弃世界首富的头衔,单单从程序员角度来讨论,比尔盖茨的代码水平如何?

其实,比尔·盖茨对写代码有一种狂热的喜好。上高中的时候,为了获得源代码,比尔·盖茨曾经去翻垃圾桶。

据了解,在1978年的Microsoft BASIC源代码6502中,比尔·盖茨实现了FOR和GOSUB的所有BASIC语句,函数,运算符,表达式评估,堆栈管理,内存管理器,数组和字符串库。

昨日,编程网站w3cschool报道,在未经微软或比尔盖茨同意的情况下,某人公开了1978年的Microsoft BASIC for 6502源代码,以及原始评论、文档和彩蛋,这是目前公开的比尔·盖茨写的最古老程序。

除了比尔盖茨外,很多互联网大佬都是程序员出身,比如马化腾、比如雷军等人。


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 "READY".
        RESTARTING THE MACHINE AT LOC 0 DURING PROGRAM
        EXECUTION CAN LEAVE THINGS MESSED UP.

        LOC OF FAC TO INTEGER AND INTEGER TO FAC 
        ROUTINES.

        "DIRECT" 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 "CHRGET"
        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)
        "FUNDSP" 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 "ISFUN".

    THE OPERATOR LIST
        THE "OPTAB" 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 "OPTAB" IS IDENTICAL.
        THE PRECEDENCES ARE ARBITRARY EXCEPT FOR THEIR
        COMPARATIVE SIZES. NOTE THAT THE PRECEDENCE FOR
        UNARY OPERATORS SUCH AS "NOT" 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 "BUF". AS SOON AS THE WHOLE LINE
        HAS BEEN TYPED IN ("INLIN" RETURNS) "CRUNCH" 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 "LET" 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 "STMDSP" (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 "ERROR". 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 "ERRTAB" 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. "FNDFOR" IS
        USED FOR FINDING "FOR" ENTRIES ON
        THE STACK. WHENEVER A "FOR" 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 "FOR" ENTRIES ALREADY ON THE STACK
        FOR THE SAME LOOP VARIABLE. IF SO, THAT "FOR" ENTRY
        AND ALL OTHER "FOR" ENTRIES THAT WERE MADE AFTER IT
        ARE ELIMINATED FROM THE STACK. THIS IS SO A
        PROGRAM THAT JUMPS OUT OF THE MIDDLE
        OF A "FOR" LOOP AND THEN RESTARTS THE LOOP AGAIN
        AND AGAIN WON'T USE UP 18 BYTES OF STACK
        SPACE EVERY TIME. THE "NEXT" CODE ALSO
        CALLS "FNDFOR" TO SEARCH FOR A "FOR" ENTRY WITH
        THE LOOP VARIABLE IN
        THE "NEXT". AT WHATEVER POINT A MATCH IS FOUND
        THE STACK IS RESET. IF NO MATCH IS FOUND A
        "NEXT WITHOUT FOR"  ERROR OCCURS. GOSUB EXECUTION
        ALSO PUTS A 5-BYTE ENTRY ON STACK.
        WHEN A RETURN IS EXECUTED "FNDFOR" IS
        CALLED WITH A VARIABLE POINTER THAT CAN'T
        BE MATCHED. WHEN "FNDFOR" HAS RUN
        THROUGH ALL THE "FOR" 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 "RETURN" CODE ELIMINATES THE
        "GOSUB" ENTRY AND ALL "FOR" 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 "NEW", "CLEAR", AND "LIST" 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 "RTS" WHICH TAKES
        EXECUTION BACK TO "NEWSTT". STATEMENTS THAT
        CREATE OR LOOK AT SEMI-PERMANENT STACK ENTRIES
        MUST GET RID OF THE RETURN ADDRESS OF "NEWSTT" AND
        JMP TO "NEWSTT" WHEN DONE. "NEWSTT" ALWAYS
        CHRGETS THE FIRST CHARACTER AFTER THE STATEMENT
        NAME BEFORE DISPATCHING. WHEN RETURNING
        BACK TO "NEWSTT" THE ONLY THING THAT
        MUST BE SET UP IS THE TEXT POINTER IN
        "TXTPTR". "NEWSTT" WILL CHECK TO MAKE SURE
        "TXTPTR" IS POINTING TO A STATEMENT TERMINATOR.
        IF A STATEMENT SHOULDN'T BE PERFORMED UNLESS
        IT IS PROPERLY FORMATTED (I.E. "NEW") 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 "NEWSTT" WILL
        DO THE JMP TO THE "SYNTAX ERROR"
        ROUTINE. IF A STATEMENT SHOULD BE STARTED
        OVER IT CAN DO LDWD OLDTXT, STWD TXTPTR RTS SINCE THE TEXT PNTR
        AT "NEWSTT" IS ALWAYS STORED IN "OLDTXT".
        THE ^C CODE STORES [CURLIN] (THE
        CURRENT LINE NUMBER) IN "OLDLIN" SINCE THE ^C CHECK
        IS MADE BEFORE THE STATEMENT POINTED TO IS
        EXECUTED. "STOP" AND "END" STORE THE TEXT POINTER
        FROM "TXTPTR", WHICH POINTS AT THEIR TERMINATING
        CHARACTER, IN "OLDTXT".

    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, "FRMEVL"
        EVALUATES THE FORMULA AND LEAVES
        THE VALUE IN THE FLOATING ACCUMULATOR (FAC).
        "TXTPTR" 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 "FRMEVL".
            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 "QCHNUM" TO CAUSE
                APPLICATION OF THE LAST OPERATOR.
                EVENTUALLY RETURN TO STEP 2
                BY RETURNING TO JUST AFTER "DOPREC".
            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+"F".

    EVAL -- THE ROUTINE TO READ A LEXEME
        "EVAL" CHECKS FOR THE DIFFERENT TYPES OF
        ENTITIES IT IS SUPPOSED TO DETECT.
        LEADING PLUSES ARE IGNORED,
        DIGITS AND "." CAUSE "FIN" (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 "PTRGET" TO BE CALLED TO GET A POINTER
        TO THE VALUE, AND THEN THE VALUE IS PUT INTO
        THE FAC. AN OPEN PARENTHESIS CAUSES "FRMEVL"
        TO BE CALLED (RECURSIVELY), AND THE ")" 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 "DIM" 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 "FOR" 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 "FOR" 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 "FOR"
        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.
        "PTRGET", THE ROUTINE WHICH RETURNS A POINTER
        TO A VARIABLE VALUE, HAS TWO IMPORTANT FLAGS. ONE IS
        "DIMFLG" WHICH INDICATES WHETHER "DIM" CALLED "PTRGET"
        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 "DIMENSIONED", 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 "SUBFLG"
        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 "PTRGET", AND "PTRGET" WILL RETURN
        WITH A TEXT POINTER POINTING TO THE "(", 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 "PTRGET" SEES A "$" AFTER THE
        NAME OF A VARIABLE, "PTRGET" 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, "STRLIT"
        IS CALLED, CAUSING A DESCRIPTOR TO BE BUILT FOR
        THE STRING. WHEN ASSIGNMENT IS MADE TO A STRING POINTING INTO
        "BUF" THE VALUE IS COPIED INTO STRING SPACE SINCE [BUF]
        IS ALWAYS CHANGING.

        STRING FUNCTIONS AND THE ONE STRING OPERATOR "+"
        ALWAYS RETURN THEIR VALUES IN STRING SPACE.
        ASSIGNING A STRING A CONSTANT VALUE IN A PROGRAM
        THROUGH A "READ" 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 "BUF", 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 "CHR$", BUT
        THE ASSIGNMENT ITSELF WILL CAUSE NO COPYING SINCE
        THE ONLY POINTER AT THE NEW STRING IS A
        TEMPORARY DESCRIPTOR CREATED BY "FRMEVL" 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 "GETSPA" 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 "GETSPA" IS A POINTER
            TO THE DESCRIPTORS OF THE ARGUMENTS.
            3) CONSTRUCT THE RESULT DESCRIPTOR IN "DSCTMP".
            "GETSPA" 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 "FRETMP".
            6) JUMP TO "PUTNEW" TO GET THE DESCRIPTOR IN
            "DSCTMP" 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 "GETSPA" 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
        "DSCTMP" 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. "MEMSIZ" 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 "REMMIN"
            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 "GETSPA" AGAIN CHECKS
        TO SEE IF [ACCA] CHARACTERS ARE AVAILABLE BETWEEN
        [STREND] AND [FRETOP]; IF NOT, AN "OUT OF STRING"
        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 "INIT" ARE ANSWERED REASONABLY, SINCE
        ONCE "INIT" FINISHES, THE LOCATIONS IT USES ARE
        USED FOR PROGRAM STORAGE. THE LAST THING "INIT" DOES IS
        CHANGE LOCATION ZERO TO BE A JUMP TO "READY" INSTEAD
        OF "INIT". ONCE THIS IS DONE THERE IS NO WAY TO RESTART
        "INIT".
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    STRSIZNUMTMP    ;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    3ADDPRC+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==2ADDPRC+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 2NUMLEV+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 BEE


 6  已被阅读了632次  楼主 2017-08-30 16:38:39
回复列表

回复:比尔·盖茨写的最古老程序曝光:BAT程序员膜拜

桂公网安备 45010302000666号 桂ICP备14001770-3号
您的IP:54.144.16.135,2018-06-20 07:40:25,Processed in 1.14062 second(s).
免责声明: 本网不承担任何由内容提供商提供的信息所引起的争议和法律责任。
Powered by HadSky 5.5.2