REM Sic64.bas v64.0a r5.2a - Symbolic Instruction Code Kit for QB64.

REM The public domain experimental Windows programming interpreter.

' declare all default variables
_DEFINE A-Z AS _FLOAT
_TITLE "SICK64"
REM $DYNAMIC

REM $Include: 'sxmath.bi'
REM $Include: 'sxript.bi'

' boolean constants
CONST Dfalse = 0#
CONST Dtrue = -1#
CONST False = 0
CONST True = -1

' color constants
CONST Black = 0
CONST Plain = 7
CONST Blue = 9
CONST Green = 10
CONST Cyan = 11
CONST Red = 12
CONST Magenta = 13
CONST Yellow = 14
CONST White = 15

' PI constants
CONST PI = 3.1415926
CONST PI2 = PI * 2 / 180

' maximum integer constant
CONST MaxInt = 32766 ' zero-based

' constant declarations (can be changed up to maxint)
CONST MaxArrays = 128
CONST MaxFNlength = 1024
CONST MaxFunctions = 26
CONST MaxHistory = 10
CONST MaxLines = 32000
CONST MaxNestGosub = 128
CONST MaxRecurse = 16
CONST MaxViolations = 1024

' constant declarations (cannot be changed)
CONST MaxFiles = 255
CONST MaxCommands = 26
CONST MaxStatements = 153

' constant declarations (should not be changed)
CONST ErrorTries = 16
CONST None = "<none>"
CONST Nul = ""
CONST PrimeKey = 29
CONST PublishDate = "07/21/2018"
CONST Release = "5.2a"
CONST Version = "64.0a"
CONST Untitled = "<untitled>"

' constant moreprompt declarations (could be changed)
CONST MorePrompt1 = "More(y/n/c)?"
CONST MorePrompt2 = "More(y/n)?"
CONST MorePrompt3 = "(y/n/q)?"
CONST MorePrompt4 = "-more-"

' declare startup error routine
ON ERROR GOTO ErrorRoutine2

' declare interrupt registers
TYPE RegTypeX
    AX AS INTEGER
    BX AS INTEGER
    CX AS INTEGER
    DX AS INTEGER
    BP AS INTEGER
    SI AS INTEGER
    DI AS INTEGER
    FL AS INTEGER
    DS AS INTEGER
    ES AS INTEGER
END TYPE

' declare interrupt functions
DECLARE SUB InterruptX(N AS INTEGER,I AS RegTypeX,O AS RegTypeX)
DECLARE SUB Absolute(N As Integer)

' interrupt registers
COMMON SHARED InregsX AS RegTypeX, OutregsX AS RegTypeX

' global variables
DIM SHARED AllowAlpha AS INTEGER
DIM SHARED AllowExtra AS INTEGER
DIM SHARED ArraySize AS INTEGER
DIM SHARED Assign AS INTEGER
DIM SHARED AutoIndent AS INTEGER
DIM SHARED AutoIndentSpaces AS INTEGER
DIM SHARED BootError AS INTEGER
DIM SHARED CaseStrng AS STRING
DIM SHARED CaseValue AS DOUBLE
DIM SHARED CaseValue1 AS DOUBLE
DIM SHARED CaseValue2 AS DOUBLE
DIM SHARED CaseValueS1 AS STRING
DIM SHARED CaseValueS2 AS STRING
DIM SHARED CommandLine AS STRING
DIM SHARED DataLine AS INTEGER
DIM SHARED DataNumber AS INTEGER
DIM SHARED DataValue AS DOUBLE
DIM SHARED DebugActive AS INTEGER
DIM SHARED DEFSEGvalue AS DOUBLE
DIM SHARED ErrorCount AS INTEGER
DIM SHARED ErrorLine AS INTEGER
DIM SHARED ErrorLine2 AS INTEGER
DIM SHARED ErrorType AS INTEGER
DIM SHARED ErrorType2 AS INTEGER
DIM SHARED ErrorValue AS INTEGER
DIM SHARED ErrorValue2 AS INTEGER
DIM SHARED ExceptStep AS DOUBLE
DIM SHARED ExceptStepIs AS INTEGER
DIM SHARED FieldVariable AS INTEGER
DIM SHARED Filename AS STRING
DIM SHARED FileNumber AS INTEGER
DIM SHARED FileNumber2 AS INTEGER
DIM SHARED FileNumber3 AS INTEGER
DIM SHARED FileSearch AS INTEGER
DIM SHARED FileSearch2 AS INTEGER
DIM SHARED FinishFor AS DOUBLE
DIM SHARED ListLines AS INTEGER
DIM SHARED Recurse AS INTEGER
DIM SHARED InDEFSEG AS INTEGER
DIM SHARED InDEFSEG2 AS INTEGER
DIM SHARED LastCursor1 AS INTEGER
DIM SHARED LastCursor2 AS INTEGER
DIM SHARED LastCursor3 AS INTEGER
DIM SHARED LastColor1 AS INTEGER
DIM SHARED LastColor2 AS INTEGER
DIM SHARED LastScreen1 AS INTEGER
DIM SHARED LastScreen2 AS INTEGER
DIM SHARED LastScreen3 AS INTEGER
DIM SHARED LastScreen4 AS INTEGER
DIM SHARED LastWidth1 AS INTEGER
DIM SHARED LastWidth2 AS INTEGER
DIM SHARED LastLine AS INTEGER
DIM SHARED LastSearchCase AS INTEGER
DIM SHARED LastSearchLine AS INTEGER
DIM SHARED LastSearchKeyword AS STRING
DIM SHARED LastToken AS INTEGER
DIM SHARED LineFeed AS INTEGER
DIM SHARED MaxErrors AS INTEGER
DIM SHARED MaxGosubs AS INTEGER
DIM SHARED Node AS INTEGER
DIM SHARED NestedGosub AS INTEGER
DIM SHARED OperatingSystem AS STRING
DIM SHARED Out2 AS STRING
DIM SHARED Out3 AS STRING
DIM SHARED Out4 AS STRING
DIM SHARED PageLength AS INTEGER
DIM SHARED Printing AS INTEGER
DIM SHARED PrinterLF AS INTEGER
DIM SHARED PrepareFilename AS STRING
DIM SHARED ProgramLine AS INTEGER
DIM SHARED ProgramName AS STRING
DIM SHARED ProgramResume AS INTEGER
DIM SHARED ProgramRunning AS INTEGER
DIM SHARED Quote AS STRING * 1
DIM SHARED Quotes AS INTEGER
DIM SHARED RunLine AS INTEGER
DIM SHARED RunType AS INTEGER
DIM SHARED StepTo AS DOUBLE
DIM SHARED SaveOnExit AS INTEGER
DIM SHARED ScreenHeight AS INTEGER
DIM SHARED ScreenMode AS INTEGER
DIM SHARED ScreenWidth AS INTEGER
DIM SHARED Strng AS STRING
DIM SHARED Token AS INTEGER
DIM SHARED TokenIndex AS INTEGER
DIM SHARED TokenList AS STRING
DIM SHARED UnlessBranch AS INTEGER
DIM SHARED UnlessValue AS DOUBLE
DIM SHARED ValueIs AS DOUBLE
DIM SHARED Visible AS INTEGER
DIM SHARED VarSeg1 AS STRING
DIM SHARED VarSeg2 AS DOUBLE
DIM SHARED WhiteSpace AS STRING

' operating system variables
DIM SHARED LINUX AS INTEGER
DIM SHARED MACOSX AS INTEGER
DIM SHARED WINDOWS AS INTEGER
DIM SHARED ANDROID AS INTEGER

' common interrupt registers
DIM SHARED AX AS DOUBLE
DIM SHARED BX AS DOUBLE
DIM SHARED CX AS DOUBLE
DIM SHARED DX AS DOUBLE
DIM SHARED BP AS DOUBLE
DIM SHARED SI AS DOUBLE
DIM SHARED DI AS DOUBLE
DIM SHARED FL AS DOUBLE
DIM SHARED DS AS DOUBLE
DIM SHARED ES AS DOUBLE

' declare prompt strings
DIM SHARED Prompt1 AS STRING
DIM SHARED Prompt2 AS STRING
DIM SHARED Prompt3 AS STRING

' program variables
DIM SHARED Commands(1 TO MaxCommands) AS STRING
DIM SHARED Statements(1 TO MaxStatements + 3) AS STRING

' program code
DIM SHARED GosubReturn(1 TO 10) AS INTEGER
DIM SHARED Program(0 TO MaxLines) AS STRING
DIM SHARED LineBreak(1 TO MaxLines) AS INTEGER

' variable break arrays
DIM SHARED VariableBreak(1 TO 26) AS INTEGER
DIM SHARED VariableValue(1 TO 26) AS DOUBLE
DIM SHARED VariableBreak2(1 TO 26) AS INTEGER
DIM SHARED VariableValue2(1 TO 26) AS STRING
DIM SHARED VariableBreak3(0 TO 26, 0 TO MaxArrays) AS INTEGER
DIM SHARED VariableValue3(0 TO 26, 0 TO MaxArrays) AS DOUBLE

' program data
DIM SHARED Arrays(0 TO 26, 0 TO MaxArrays) AS DOUBLE
DIM SHARED Definitions(0 TO MaxFunctions) AS STRING
DIM SHARED Strngs(0 TO 26) AS STRING
DIM SHARED Variables(0 TO 26) AS DOUBLE

' multi-dimensional command history arrays
DIM SHARED HistoryCount2(1 TO 3) AS INTEGER
DIM SHARED History2(1 TO 3, 1 TO MaxHistory) AS STRING * 256

' multi-dimensional command history variable
DIM SHARED Temp0 AS INTEGER

' file areas
DIM SHARED FieldArray(1 TO 255) AS STRING
DIM SHARED FileFields(1 TO 255) AS STRING

' graphics areas
DIM SHARED GraphicsScreen(1 TO 10) AS INTEGER
DIM SHARED VarSeg3(1 TO 10) AS INTEGER

' temp directory
DIM SHARED DRX AS STRING

' declare library constants.
CONST MAX_PATH = 260
CONST INVALID_HANDLE_VALUE = -1
CONST ERROR_FILE_NOT_FOUND = 2
CONST ERROR_NO_MORE_FILES = &H12
CONST ByteDivisor = 1024

' declare library structures.
TYPE FILETIME
    dwLowDateTime AS _UNSIGNED LONG
    dwHighDateTime AS _UNSIGNED LONG
END TYPE

TYPE SYSTEMTIME
    wYear AS INTEGER
    wMonth AS INTEGER
    wDayOfWeek AS INTEGER
    wDay AS INTEGER
    wHour AS INTEGER
    wMinute AS INTEGER
    wSecond AS INTEGER
    wMilliseconds AS INTEGER
END TYPE

TYPE WIN32_FIND_DATAA
    dwFileAttributes AS _UNSIGNED LONG
    ftCreationTime AS FILETIME
    ftLastAccessTime AS FILETIME
    ftLastWriteTime AS FILETIME
    nFileSizeHigh AS _UNSIGNED LONG
    nFileSizeLow AS _UNSIGNED LONG
    dwReserved0 AS _UNSIGNED LONG
    dwReserved1 AS _UNSIGNED LONG
    cFileName AS STRING * MAX_PATH
    cAlternateFileName AS STRING * 14
END TYPE

' declare external libraries.
DECLARE DYNAMIC LIBRARY "kernel32"
    FUNCTION FindFirstFileA~%& (BYVAL lpFileName~%&, BYVAL lpFindFileData~%&)
    FUNCTION FindNextFileA& (BYVAL hFindFile~%&, BYVAL lpFindFileData~%&)
    FUNCTION FindClose& (BYVAL hFindFile~%&)
    FUNCTION FileTimeToSystemTime& (lpFileTime AS FILETIME, lpSystemTime AS SYSTEMTIME)
    FUNCTION GetVolumeInformationA& (lpRootPathName$, lpVolumeNameBuffer$, BYVAL nVolumeNameSize~&, lpVolumeSerialNumber~&, lpMaximumComponentLength~&, lpFileSystemFlags~&, lpFileSystemNameBuffer$, BYVAL nFileSystemNameSize&)
    FUNCTION GetDiskFreeSpaceA& (f$, sectors&, bytes&, free&, total&)
    FUNCTION GetDiskFreeSpaceExA& (filename$, free AS _UNSIGNED _INTEGER64, total AS _UNSIGNED _INTEGER64, free2 AS _UNSIGNED _INTEGER64)
END DECLARE

DECLARE LIBRARY
    FUNCTION GetFileAttributes& (f$)
    FUNCTION SetFileAttributes& (f$, BYVAL a&)
    FUNCTION GetDriveType& (d$)
    FUNCTION GetShortPathName& (InP$, OutP$, BYVAL length&)
    FUNCTION GetModuleFileNameA (BYVAL Module AS LONG, FileName AS STRING, BYVAL nSize AS LONG)
END DECLARE

' declare library variables.
DIM SHARED finddata AS WIN32_FIND_DATAA
DIM SHARED finddata2 AS WIN32_FIND_DATAA
DIM SHARED finddata3 AS WIN32_FIND_DATAA
DIM SHARED hfind AS _UNSIGNED _OFFSET
DIM SHARED hfind2 AS _UNSIGNED _OFFSET
DIM SHARED hfind3 AS _UNSIGNED _OFFSET
DIM SHARED SysTime AS SYSTEMTIME
DIM SHARED DriveType AS STRING

' initialize common variables
MaxGosubs = 10
PageLength = 23
ProgramName = None
Quote = CHR$(34)
SaveOnExit = True
TokenList = " -+*/\^()[]{}<>=|&!%~?:#@`;,'" + Quote
WhiteSpace = CHR$(32) + CHR$(9) ' can be changed

' initialize default screen variables
LastScreen1 = 0
LastScreen2 = 1
LastScreen3 = 0
LastScreen4 = 0

' initialize local screen variables
ScreenMode = 0
ScreenHeight = 25
ScreenWidth = 80

' reset multi-dimensional command history arrays
FOR VarQ1 = 1 TO 3
    HistoryCount2(VarQ1) = 0
    FOR VarQ2 = 1 TO MaxHistory
        History2(VarQ1, VarQ2) = Nul
    NEXT
NEXT

' reseed randomizer
RANDOMIZE TIMER

' get environment variables
IF ANDROID THEN
    SYSTEM
END IF
Var$ = ENVIRON$("SICPAGELENGTH")
IF LEN(Var$) THEN
    Temp# = INT(VAL(Var$))
    IF Temp# > 0# AND Temp# <= 32767# THEN
        PageLength = CINT(Temp#)
    END IF
END IF
Var$ = ENVIRON$("SICSAVEONEXIT")
IF LEN(Var$) THEN
    SaveOnExit = False
END IF
Prompt1 = ">"
Var$ = ENVIRON$("SICPROMPT1")
IF LEN(Var$) THEN
    Prompt1 = Var$
END IF
Prompt2 = ":"
Var$ = ENVIRON$("SICPROMPT2")
IF LEN(Var$) THEN
    Prompt2 = Var$
END IF
Prompt3 = "?"
Var$ = ENVIRON$("SICPROMPT3")
IF LEN(Var$) THEN
    Prompt3 = Var$
END IF
Var$ = ENVIRON$("SICIGNORE")
IF LEN(Var$) THEN
    BootError = True
END IF

' declares all 26 Sic64 commands
DATA "ANALYZE","FILES","HELP","INDENT","KILL","LIST","LOAD","NEW","PRINT","QUIT"
DATA "RENUMBER","RUN","SAVE","WHATIS","CONTINUE","DEBUG","SHELL","SEARCH","SET"
DATA "TIME","DATE","CLOCK","DIRS","DRIVES","VERSION","AUTOINDENT"

' read in commands
FOR Temp = 1 TO MaxCommands
    READ Commands$(Temp)
NEXT

' declares all Sic64 statements on left side of equation,
' each statement listed contains its own subroutine.
' listed in rows of ten.
DATA "'","ENDIF","END IF","STOP","REM","MID$","LEFT$","RIGHT$","PRINT #","DPRINT"
DATA "LPRINT USING","SPRINT","UPRINT","INPUT;","FORIF","FOR","NEXTIF","NEXT","CONTINUE FORIF","CONTINUE FOR"
DATA "EXIT FORIF","EXIT FOR","DO UNTIL","LOOP WHILE","EXIT DO","CONTINUE DO","GOTO","GOSUB","RETURN","DO WHILE"
DATA "DO","OFF","IF","ELSEIF","CASEIF ELSE","CASEIF","SELECT CASE","END SELECTIF","BEEP","SOUND"
DATA "COLOR","LOCATE","CLS","SCREEN","WIDTH","WRITE #","LINE INPUT;","LINE INPUT #","INPUT #","WEND"
DATA "WHILE","CONTINUE WHILE","EXIT WHILE","ELSE","LOOP UNTIL","LOOPIF","END LOOPIF","EXIT LOOPIF","LOOP","RANDOMIZE"
DATA "POKE","INT86","DEFSEG","ABSOLUTE","OUT","WAIT","SLEEP","PAUSE","SELECTIF CASE","END SELECT"
DATA "CASE ELSE","CASE","CONTINUE LOOPIF","END","CLEAR","SYSTEM","SWAP","ERROR","ON ERROR GOTO","ON ERROR RESUME PREVIOUS"
DATA "ON ERROR RESUME SAME","ON ERROR RESUME NEXT","ON ERROR STOP","RESUME PREVIOUS","RESUME SAME","RESUME NEXT","RESUME","ON","DATE$","TIME$"
DATA "CHDRIVE","CD","CHDIR","MD","MKDIR","RD","RMDIR","KILL","DELETE","RENAME"
DATA "NAME","SHELL","CHAIN","LET","CLOSE #","OPEN #","FIELD #","WRITE","PRINT USING","INPUT"
DATA "LINE INPUT","LSET #","RSET #","PUT #","GET #","READ #","DATA","READ","RESTORE","CIRCLE STEP"
DATA "LINE STEP","PSET STEP","PRESET STEP","PAINT STEP","DRAW","PLAY","GET STEP","PUT STEP","BSAVE","BLOAD"
DATA "VIEW SCREEN","VIEW","WINDOW SCREEN","WINDOW","CIRCLE","LINE","CLOSE","DEF FN","ENVIRON","PAINT"
DATA "PSET","PRESET","GET","PUT","DIM","COMMON","DECLARE","LOCK #","UNLOCK #","PRINT"
DATA "LPRINT","TRIANGLE","POLYGON"

REM  "This program is public domain software written by:"
DATA "Author: Erik Jon Oredson AS. CSci"
DATA "Email: eoredson@gmail.com"
DATA "Url: www.filegate.net"
REM  "Note: Cookies are delicious. So are cats."

' read in statements
FOR Temp = 1 TO MaxStatements + 3
    READ Statements$(Temp)
NEXT

' declares indent structure types
IndentData:
' 1=indent right
DATA "SELECTIF CASE",1
DATA "DO WHILE",1
DATA "DO",1
DATA "IF",1
DATA "SELECT CASE",1
DATA "DO UNTIL",1
DATA "FORIF",1
DATA "FOR",1
DATA "WHILE",1
DATA "LOOPIF",1
' -1=indent left
DATA "ENDIF",-1
DATA "END IF",-1
DATA "NEXTIF",-1
DATA "NEXT",-1
DATA "LOOP UNTIL",-1
DATA "LOOP WHILE",-1
DATA "END SELECT",-1
DATA "WEND",-1
DATA "END LOOPIF",-1
DATA "LOOP",-1
DATA "END SELECTIF",-1
' -2=indent left, then right
DATA "ELSE",-2
DATA "CASE",-2
DATA "EOF",0

AnalyzeData1:
DATA "IF","ENDIF"
DATA "DO","LOOP"
DATA "FOR","NEXT"
DATA "WHILE","WEND"
DATA "FORIF","NEXTIF"
DATA "LOOPIF","END LOOPIF"
DATA "SELECT CASE","END SELECT"
DATA "SELECTIF CASE","END SELECTIF"

AnalyzeData2:
DATA "IF","ENDIF","ELSE","ELSEIF"
DATA "SELECT CASE","END SELECT","CASE ELSE","CASE"
DATA "SELECTIF CASE","END SELECTIF","CASEIF ELSE","CASEIF"

AnalyzeData3:
DATA "DO","LOOP","EXIT DO","CONTINUE DO"
DATA "FOR","NEXT","EXIT FOR","CONTINUE FOR"
DATA "WHILE","WEND","EXIT WHILE","CONTINUE WHILE"
DATA "FORIF","NEXTIF","EXIT FORIF","CONTINUE FORIF"
DATA "LOOPIF","END LOOPIF","EXIT LOOPIF","CONTINUE LOOPIF"

' parse command line
Filename = COMMAND$
IF Filename = "/?" OR Filename = "-?" THEN
    GOTO BootUsage
END IF
Filename = UCASE$(Filename)
Var = INSTR(Filename, "/Z")
IF Var THEN
    BootError = True
    Filename = LEFT$(Filename, Var - 1) + MID$(Filename, Var + 2)
END IF
Filename = RTRIM$(Filename)
Filename = LTRIM$(Filename)
IF LEFT$(Filename, 1) = "/" THEN
    Node = INT(VAL(MID$(Filename, 2, 1)))
    IF Node >= 1 AND Node <= 9 THEN
        Filename = MID$(Filename, 3)
    ELSE
        GOTO BootUsage
    END IF
END IF
Filename = RTRIM$(Filename)
Filename = LTRIM$(Filename)
IF LEN(Filename) THEN
    IF LEFT$(Filename, 1) = CHR$(34) THEN
        Filename = MID$(Filename, 2)
        IF RIGHT$(Filename, 1) = CHR$(34) THEN
            Filename = LEFT$(Filename, LEN(Filename) - 1)
        ELSE
            GOTO BootUsage
        END IF
    END IF
    IF Filename = Nul THEN
        GOTO BootUsage
    END IF
    IF _FILEEXISTS(Filename) = 0 THEN
        GOTO BootUsage
    END IF
    ProgramResume = True
END IF

' declare main input loop error routine
ON ERROR GOTO ErrorRoutine

' check system type
OS$ = _OS$
IF INSTR(OS$, "[LINUX]") THEN
    LINUX = -1
END IF
IF INSTR(OS$, "[MACOSX]") THEN
    MACOSX = -1
END IF
IF INSTR(OS$, "[WINDOWS]") THEN
    WINDOWS = -1
END IF
IF INSTR(OS$, "[ANDROID]") THEN
    ANDROID = -1
END IF

' check temp directory.
FX$ = "C:\TEMP"
IF Node THEN
    FX$ = "C:\TEMP" + LTRIM$(STR$(Node))
END IF
IF _DIREXISTS(FX$) = 0 THEN
    IF _FILEEXISTS(FX$) THEN
        KILL FX$
    END IF
    MKDIR FX$
END IF
DRX = FX$ + "\"

' ProgramResume variable:
'   -1 = command line program
'    0 = immediate interpreter

' run program from command line
IF LEN(Filename) THEN
    ProgramResume = True
    CALL NewProgram
    CALL ReadProgram
    RunType = False
    CALL RunProgram(False)
    CALL StopProgram
END IF

' display logon banner
COLOR White, Black
PRINT "SIC64 v" + Version + " r" + Release + ": for QB64: ";
PRINT "The Symbolic Instruction Code Interpreter."
PRINT "Type 'Quit' to return to system."

' declare main input loop error routine
ON ERROR GOTO ErrorRoutine

' enter the Sic64 engine
ErrorResume:

' check which function started Sic
IF ProgramResume THEN
    CALL EndProgram
    CALL StopProgram
END IF
IF FileNumber THEN
    CLOSE #FileNumber
    FileNumber = False
END IF

' declare main input loop error routine
ON ERROR GOTO ErrorRoutine

' enter the Sic64 programming interface
DO
    ' get input
    ValidCommand = False
    Visible = 1
    COLOR Yellow, Black
    LOCATE , 1, 1
    PRINT Prompt1;
    LOCATE , , 1
    Temp0 = 1
    Out2 = RTRIM$(KeyboardLine2$)
    PRINT
    IF Out2 = Nul THEN
        ValidCommand = True
    ELSE
        ' check preceding line number
        CALL EnterProgramLine
        IF Assign THEN
            ValidCommand = True
        ELSE

            ' get environment variable
            Param2$ = Nul
            Var$ = ENVIRON$("SICCMDLINE")
            IF LEN(Var$) THEN
                Param2$ = Var$
            END IF

            ' store parameter
            Param$ = Nul
            Out3 = Out2
            Out2 = UCASE$(Out2)
            Parameter = INSTR(Out2, " ")
            IF Parameter THEN
                Param$ = MID$(Out2, Parameter + 1)
                Param2$ = MID$(Out3, Parameter + 1)
                Out2 = LEFT$(Out2, Parameter - 1)
            END IF

            ' compare to command list
            ValidCommand = False
            FOR CommandNumber = 1 TO MaxCommands
                IF Out2 = Commands(CommandNumber) OR Out2 = LEFT$(Commands(CommandNumber), 3) THEN

                    ' check command uses currently loaded program
                    SELECT CASE CommandNumber
                        CASE 1, 4, 6, 8, 9, 11, 12, 13, 15, 18
                            IF ProgramName = None THEN
                                COLOR White, Black
                                PRINT "No program loaded."
                                ValidCommand = True
                                EXIT FOR
                            END IF
                    END SELECT

                    ' check command has no parameter to specify
                    SELECT CASE CommandNumber
                        CASE 1, 3, 8, 10, 15, 16, 18, 20, 21, 22, 25, 26
                            IF LEN(Param$) THEN
                                EXIT FOR
                            END IF
                    END SELECT

                    ' process command
                    ValidCommand = True
                    SELECT CASE CommandNumber
                        CASE 1 ' analyze
                            CALL PrepareProgram
                            CALL AnalyzeProgram(-1, VarX, Var1$)
                            CALL NewProgram
                            Filename = PrepareFilename
                            CALL ReadProgram
                            KILL PrepareFilename
                        CASE 2 ' files
                            CALL ListFiles(Param$, True)
                            ErrorType2 = 0
                        CASE 3 ' help
                            CALL ListHelp
                        CASE 4 ' indent
                            CALL IndentProgram(0, INT(VAL(Param$)))
                        CASE 5 ' kill
                            CALL DeleteProgram(Param$)
                        CASE 6 ' list
                            StartLine = 1
                            CALL CountLines(LastLine)
                            StopLine = LastLine
                            IF LEN(Param$) THEN
                                Comma = INSTR(Param$, ",")
                                IF Comma THEN
                                    StartLine = INT(VAL(LEFT$(Param$, Comma - 1)))
                                    StopLine = INT(VAL(MID$(Param$, Comma + 1)))
                                ELSE
                                    StartLine = INT(VAL(Param$))
                                    StopLine = LastLine
                                END IF
                            END IF
                            CALL ListProgram(StartLine, StopLine, False)
                        CASE 7 ' load
                            CALL LoadProgram(Param$)
                        CASE 8 ' new
                            IF SaveOnExit THEN
                                CALL SaveCurrent
                            END IF
                            LastSearchLine = False
                            CALL NewProgram
                            ProgramName = None
                            COLOR White, Black
                            PRINT "Program cleared."
                        CASE 9 ' print
                            StartLine = 1
                            CALL CountLines(LastLine)
                            StopLine = LastLine
                            IF LEN(Param$) THEN
                                Comma = INSTR(Param$, ",")
                                IF Comma THEN
                                    StartLine = INT(VAL(LEFT$(Param$, Comma - 1)))
                                    StopLine = INT(VAL(MID$(Param$, Comma + 1)))
                                ELSE
                                    StartLine = INT(VAL(Param$))
                                    StopLine = LastLine
                                END IF
                            END IF
                            CALL ListProgram(StartLine, StopLine, True)
                        CASE 10 ' quit
                            CALL QuitProgram
                            END
                        CASE 11 ' renumber
                            StartLine = False
                            IncrementValue = False
                            IF LEN(Param$) THEN
                                Comma = INSTR(Param$, ",")
                                IF Comma THEN
                                    StartLine = INT(VAL(LEFT$(Param$, Comma - 1)))
                                    IncrementValue = INT(VAL(MID$(Param$, Comma + 1)))
                                END IF
                            END IF
                            CALL RenumberProgram(StartLine, IncrementValue)
                        CASE 12 ' run
                            CommandLine = Param2$
                            IF LEFT$(UCASE$(Param2$), 5) = "LINE=" THEN
                                StartNumber = INT(VAL(MID$(Param2$, 6)))
                            ELSE
                                StartNumber = False
                            END IF
                            COLOR White, Black
                            PRINT "Starting program: " + ProgramName
                            RunType = False
                            CALL RunProgram(StartNumber)
                            COLOR White, Black
                            IF POS(0) > 1 THEN
                                PRINT
                            END IF
                            PRINT "Program run ended."
                        CASE 13 ' save
                            CALL SaveProgram(Param$)
                        CASE 14 ' whatis
                            CALL CountLines(LastLine)
                            CALL WhatisCommand(Param$)
                        CASE 15 ' continue
                            RunType = True
                            IF RunLine > MaxLines THEN
                                COLOR White, Black
                                PRINT "Can't continue."
                            ELSE
                                CALL CountLines(V%)
                                IF RunLine >= V% THEN
                                    COLOR White, Black
                                    PRINT "Can't continue."
                                ELSE
                                    COLOR White, Black
                                    PRINT "Continuing program: " + ProgramName
                                    CALL RunProgram(0)
                                END IF
                            END IF
                        CASE 16 ' debug
                            CALL DebugCommand
                        CASE 17 ' shell
                            CALL ShellProgram2(Param$)
                        CASE 18 ' search
                            CALL SearchProgram
                        CASE 19 ' set
                            CALL SetPrompts
                        CASE 20
                            COLOR White, Black
                            PRINT TIME$
                        CASE 21
                            COLOR White, Black
                            PRINT DATE$
                        CASE 22
                            COLOR White, Black
                            PRINT DATE$ + " " + TIME$
                        CASE 23 ' dirs
                            CALL ListFiles(Param$, False)
                            ErrorType2 = 0
                        CASE 24 ' drives
                            CALL ListDrives(Param$, False)
                        CASE 25 ' version
                            COLOR White, Black
                            PRINT "SIC64 v" + Version + " r" + Release + " for QB64"
                            PRINT "Published "; PublishDate
                            PRINT "System: "; _OS$
                        CASE 26 ' autoindent
                            AutoIndent = NOT AutoIndent
                            IF AutoIndent = 0 THEN
                                PRINT "Autoindent off."
                            END IF
                            IF AutoIndent THEN
                                PRINT "Enter spaces(1-9)? ";
                                X$ = Nul
                                DO
                                    _LIMIT 100
                                    X$ = INKEY$
                                    IF LEN(X$) THEN
                                        IF X$ >= "1" AND X$ <= "9" THEN
                                            AutoIndentSpaces = VAL(X$)
                                            PRINT
                                            PRINT "Autoindent on."
                                            EXIT DO
                                        END IF
                                    END IF
                                LOOP
                            END IF
                    END SELECT
                    EXIT FOR
                END IF
            NEXT
        END IF
    END IF
    IF ValidCommand = False THEN
        COLOR White, Black
        PRINT "Type 'Help' for information."
    END IF
LOOP
END

EquateTrap:
ErrorLine = ProgramLine
ErrorValue = ERR
ErrorValue2 = ERR
SELECT CASE ErrorType
    CASE -1 ' previous
        DO
            ProgramLine = ProgramLine - 1
            IF LEN(STRIM$(Program$(ProgramLine))) THEN
                ProgramLine = ProgramLine - 1
                ErrorLine = 0
                RESUME NEXT
            END IF
            IF ProgramLine <= False THEN
                EXIT DO
            END IF
        LOOP
        ErrorLine = 0
    CASE -2 ' same
        ProgramLine = ProgramLine - 1
        ErrorLine = 0
        RESUME NEXT
    CASE -3 ' next
        DO
            ProgramLine = ProgramLine + 1
            IF LEN(STRIM$(Program$(ProgramLine))) THEN
                ProgramLine = ProgramLine - 1
                ErrorLine = 0
                RESUME NEXT
            END IF
            IF ProgramLine >= LastLine THEN
                ProgramLine = LastLine
                ErrorLine = 0
                RESUME NEXT
            END IF
        LOOP
        ErrorLine = 0
    CASE 0 ' stop
        Eat$ = Nul
    CASE IS > 0 ' line number
        ProgramLine = ErrorType
        IF LEN(STRIM$(Program$(ProgramLine))) THEN
            ProgramLine = ProgramLine - 1
            RESUME NEXT
        END IF
END SELECT
PrinterLF = False
Printing = False
ProgramLine = MaxLines
IF POS(0) > 1 THEN
    PRINT
END IF
CALL ResetScreen
Out2 = Nul
IF BootError = False THEN
    CALL DisplayError
END IF
CALL KeyPrompt
ProgramLine = LastLine
_TITLE "SICK64"

' read original program
IF ProgramRunning THEN
    CALL RestoreProgram
END IF
ProgramRunning = 0
RESUME ErrorResume

' display boot usage and quit
BootUsage:
COLOR White, Black
PRINT "SIC64 v" + Version + " r" + Release + " Usage: for QB64:"
COLOR Yellow, Black
PRINT "SIC64 [/n] [/Z]"
COLOR Green, Black
PRINT "  Starts SIC"
COLOR Yellow, Black
PRINT "SIC64 [/n] [/Z] <program name>"
COLOR Green, Black
PRINT "  Starts SIC64 and runs program."
COLOR White, Black
PRINT "(optional /n is node 1 to 9)"
PRINT "(optional /Z ignores errors)"
COLOR Plain, Black
PRINT "Returning to System:"
CALL StopProgram
END

' standard error trap for all Sic64 functions.
ErrorRoutine:

' check share violation
IF ErrorType2 THEN
    IF ERR = 70 THEN
        ErrorCount = ErrorCount + 1
        IF ErrorCount < MaxViolations THEN ' could use timer
            RESUME
        END IF
    END IF
END IF

' reset variables
ErrorCount = 0
PrinterLF = False
Printing = False
ErrorLine = ProgramLine
ErrorValue = ERR
ErrorValue2 = ERR
IF POS(0) > 1 THEN
    PRINT
END IF
Out2 = Nul
IF BootError = False THEN
    CALL DisplayError
END IF
CALL KeyPrompt
InDEFSEG = False
ProgramLine = LastLine
_TITLE "SICK64"

' read original program
IF ProgramRunning THEN
    CALL RestoreProgram
END IF
ProgramRunning = 0
RESUME ErrorResume

' standard startup error trap.
ErrorRoutine2:
IF ProgramResume = False THEN
    PRINT "SIC64 is terminating because of an error loading."
    PRINT "Returning to system with error:";
    SELECT CASE ERR
        CASE 7
            PRINT " Out of memory."
            PRINT "Free more RAM and restart."
        CASE 14
            PRINT " Out of string space."
            PRINT "Free more RAM and restart."
        CASE ELSE
            PRINT ERR
    END SELECT
END IF
IF ProgramResume THEN
    PRINT "Error"; ERR
END IF
COLOR 7, 0
END

' gets last line in program
SUB CountLines (Temp1%)
    Temp1% = False
    FOR Temp2% = MaxLines TO 1 STEP -1
        Temp1$ = Program$(Temp2%)
        Temp1$ = STRIM$(Temp1$)
        IF LEN(Temp1$) THEN
            EXIT FOR
        END IF
    NEXT
    Temp1% = Temp2%
END SUB

' displays error message
SUB DisplayError

    ' check error value range
    SELECT CASE ErrorValue
        CASE 1
            Var$ = "Internal Error #001: Next without For."
        CASE 2
            Var$ = "Error #002: Line%1: Syntax error."
        CASE 3
            Var$ = "Internal Error #003: Line%1: Return without Gosub."
        CASE 4
            Var$ = "Internal Error #004: Line%1: Out of Data."
        CASE 5
            Var$ = "Error #005: Line%1: Illegal function call."
        CASE 6
            Var$ = "Error #006: Line%1: Overflow."
        CASE 7
            Var$ = "Error #007: Line%1: Out of memory."
        CASE 8
            Var$ = "Internal Error #008: Label not defined."
        CASE 9
            Var$ = "Error #009: Line%1: Subscript out of range."
        CASE 10
            Var$ = "Internal Error #010: Duplicate definition."
        CASE 11
            Var$ = "Error #011: Line%1: Division by zero."
        CASE 12
            Var$ = "Internal Error #012: Illegal in direct mode."
        CASE 13
            Var$ = "Internal Error #013: Type mismatch."
        CASE 14
            Var$ = "Error #014: Line%1: Out of string space."
        CASE 15
            Var$ = "Error #015: Line%1: Invalid Pset statement."
        CASE 16
            Var$ = "Error #016: Line%1: String formula too complex."
        CASE 17
            Var$ = "Reserved Error #017: Cannot continue."
        CASE 18
            Var$ = "Internal Error #018: Function not defined."
        CASE 19
            Var$ = "Error #019: Line%1: No RESUME."
        CASE 20
            Var$ = "Error #020: Line%1: RESUME without error."
        CASE 21
            Var$ = "Error #021: Line%1: Syntax error specifying filename to open."
        CASE 22
            Var$ = "Error #022: Line%1: Syntax error specifying filename to close."
        CASE 23
            Var$ = "Error #023: Line%1: Syntax error specifying filename field."
        CASE 24
            Var$ = "Error #024: Line%1: Device timeout."
        CASE 25
            Var$ = "Error #025: Line%1: Device fault."
        CASE 26
            Var$ = "Internal Error #026: For without Next."
        CASE 27
            Var$ = "Error #027: Line%1: Out of paper."
        CASE 28
            Var$ = "Error #028: Line%1: Invalid LINE statement."
        CASE 29
            Var$ = "Internal Error #029: While without Wend."
        CASE 30
            Var$ = "Internal Error #030: Wend without While."
        CASE 31
            Var$ = "Error #031: Line%1: Syntax error writing to file."
        CASE 32
            Var$ = "Error #032: Line%1: Syntax error printing to file."
        CASE 33
            Var$ = "Internal Error #033: Duplicate label."
        CASE 34
            Var$ = "Error #034: Line%1: Syntax error inputing from file."
        CASE 35
            Var$ = "Internal Error #035: Subprogram not defined."
        CASE 36
            Var$ = "Error #036: Line%1: Syntax error line inputing from file."
        CASE 37
            Var$ = "Internal Error #037: Argument-count mismatch."
        CASE 38
            Var$ = "Error #038: Line%1: Array not defined."
        CASE 39
            Var$ = "Error #039: Line%1: Invalid CIRCLE statement."
        CASE 40
            Var$ = "Error #040: Line%1: Variable required."
        CASE 41
            Var$ = "Error #041: Line%1: Invalid Lset statement."
        CASE 42
            Var$ = "Error #042: Line%1: Invalid Rset statement."
        CASE 43
            Var$ = "Error #043: Line%1: Invalid Put statement."
        CASE 44
            Var$ = "Error #044: Line%1: Invalid Get statement."
        CASE 45
            Var$ = "Error #045: Line%1: Invalid Read statement."
        CASE 46
            Var$ = "Error #046: Line%1: Invalid Draw statement."
        CASE 47
            Var$ = "Error #047: Line%1: Invalid Play statement."
        CASE 48
            Var$ = "Error #048: Line%1: Invalid Paint statement."
        CASE 49
            Var$ = "Error #049: Line%1: Invalid Get/Put statement."
        CASE 50
            Var$ = "Error #050: Line%1: Field overflow."
        CASE 51
            Var$ = "Internal compiler error #051."
        CASE 52
            Var$ = "Error #052: Line%1: Bad file name or number."
        CASE 53
            Var$ = "Error #053: Line%1: File not found."
        CASE 54
            Var$ = "Error #054: Line%1: Bad file mode."
        CASE 55
            Var$ = "Error #055: Line%1: File already open."
        CASE 56
            Var$ = "Error #056: Line%1: Field statement active."
        CASE 57
            Var$ = "Error #057: Line%1: Device I/O error."
        CASE 58
            Var$ = "Error #058: Line%1: File already exists."
        CASE 59
            Var$ = "Error #059: Line%1: Bad record length."
        CASE 60
            Var$ = "Error #060: Line%1: Invalid Bsave/Bload statement."
        CASE 61
            Var$ = "Error #061: Line%1: Disk full."
        CASE 62
            Var$ = "Error #062: Line%1: Input past end of file."
        CASE 63
            Var$ = "Error #063: Line%1: Bad record number."
        CASE 64
            Var$ = "Error #064: Line%1: Bad file name."
        CASE 65
            Var$ = "Error #065: Line%1: Invalid Data statement."
        CASE 66
            Var$ = "Error #066: Line%1: Out of data."
        CASE 67
            Var$ = "Error #067: Line%1: Too many files."
        CASE 68
            Var$ = "Error #068: Line%1: Device unavailable."
        CASE 69
            Var$ = "Error #069: Line%1: Communication buffer overflow."
        CASE 70
            Var$ = "Error #070: Line%1: File permission denied."
        CASE 71
            Var$ = "Error #071: Line%1: Disk not ready."
        CASE 72
            Var$ = "Error #072: Line%1: Disk-media error."
        CASE 73
            Var$ = "Internal Error #073: Feature unavailable."
        CASE 74
            Var$ = "Error #074: Line%1: Rename across disks."
        CASE 75
            Var$ = "Error #075: Line%1: Path/File access error."
        CASE 76
            Var$ = "Error #076: Line%1: Path not found."
        CASE 77
            Var$ = "Error #077: Line%1: Invalid View statement."
        CASE 78
            Var$ = "Error #078: Line%1: Invalid Window statement."
        CASE 80
            Var$ = "Internal Error #080: Feature removed."
        CASE 81
            Var$ = "Error #081: Line%1: Invalid name."
        CASE 82
            Var$ = "Reserved Error #082: Table not found."
        CASE 83
            Var$ = "Reserved Error #083: Index not found."
        CASE 84
            Var$ = "Reserved Error #084: Invalid column."
        CASE 85
            Var$ = "Reserved Error #085: No current record."
        CASE 86
            Var$ = "Reserved Error #086: Duplicate value for unique index."
        CASE 87
            Var$ = "Reserved Error #087: Invalid operation on null index."
        CASE 88
            Var$ = "Reserved Error #088: Database needs repair."
        CASE 89
            Var$ = "Reserved Error #089: Insufficient ISAM buffers."
        CASE 91
            Var$ = "Error #091: Line%1: Unknown statement."
        CASE 92
            Var$ = "Error #092: Line%1: Whatis: %2."
        CASE 97
            Var$ = "Error #097: Line%1: Mismatched for/next."
        CASE 98
            Var$ = "Error #098: Line%1: Mismatched do/loop."
        CASE 99
            Var$ = "Error #099: Line%1: Missing line number."
        CASE 100
            Var$ = "Error #100: Line%1: Unmatched gosub."
        CASE 101
            Var$ = "Error #101: Error accessing file."
        CASE 102
            Var$ = "Error #102: Line%1: Mismatched select/end select."
        CASE 103
            Var$ = "Error #103: Line%1: Mismatched forif/nextif."
        CASE 104
            Var$ = "Error #104: Line%1: Mismatched loopif/endloopif."
        CASE 105
            Var$ = "Error #105: Line%1: Mismatched selectif/end selectif."
        CASE 110
            Var$ = "Error #110: Line%1: Unknown swap statement."
        CASE 111
            Var$ = "Error #111: Line%1: Record size overflow."
        CASE 112
            Var$ = "Error #112: Line%1: Error chaining to program."
        CASE 113
            Var$ = "Error #113: Line%1: Error naming file."
        CASE 114
            Var$ = "Error #114: Line%1: Error killing file."
        CASE 115
            Var$ = "Error #115: Line%1: Error changing directory."
        CASE 116
            Var$ = "Error #116: Line%1: Error making directory."
        CASE 117
            Var$ = "Error #117: Line%1: Error removing directory."
        CASE 118
            Var$ = "Error #118: Line%1: Error setting date."
        CASE 119
            Var$ = "Error #119: Line%1: Error setting time."
        CASE 120
            Var$ = "Error #120: Line%1: Error changing drive."
        CASE 121
            Var$ = "Error #121: Line%1: Error using OUT statement."
        CASE 122
            Var$ = "Error #122: Line%1: Error using WAIT statement."
        CASE 123
            Var$ = "Error #123: Line%1: Error using ABSOLUTE statement."
        CASE 124
            Var$ = "Error #124: Line%1: Error using POKE statement."
        CASE 125
            Var$ = "Error #125: Line%1: Error using DEFSEG statement."
        CASE 126
            Var$ = "Error #126: Line%1: Error specifying file handle number."
        CASE 127
            Var$ = "Error #127: Line%1: Error specifying hexidecimal number."
        CASE 128
            Var$ = "Error #128: Line%1: Error specifying octal number."
        CASE 129
            Var$ = "Error #129: Line%1: Error specifying binary number."
        CASE 130
            Var$ = "Error #130: Line%1: Error specifying decimal value."
        CASE 131
            Var$ = "Error #131: Line%1: Error specifying numeric value."
        CASE 132
            Var$ = "Error #132: Line%1: Error specifying factorial value."
        CASE 133
            Var$ = "Error #133: Line%1: Error specifying quoted value."
        CASE 134
            Var$ = "Error #134: Line%1: Bad input variable."
        CASE 135
            Var$ = "Error #135: Line%1: Mismatched data."
        CASE 136
            Var$ = "Error #136: Line%1: Too few input variables."
        CASE 137
            Var$ = "Error #137: Line%1: Too many input variables."
        CASE 138
            Var$ = "Error #138: Line%1: Missing left parenthesis."
        CASE 139
            Var$ = "Error #139: Line%1: Missing right parenthesis."
        CASE 140
            Var$ = "Error #140: Line%1: Specified double exponent."
        CASE 141
            Var$ = "Error #141: Line%1: Missing exponent value."
        CASE 142
            Var$ = "Error #142: Line%1: Bad exponent unary sign."
        CASE 143
            Var$ = "Error #143: Line%1: Bad exponent decimal point."
        CASE 144
            Var$ = "Error #144: Line%1: Bad DEF FN declaration."
        CASE 145
            Var$ = "Error #145: Line%1: Unknown line number."
        CASE 146
            Var$ = "Error #146: Line%1: Bad WIDTH statement."
        CASE 147
            Var$ = "Error #147: Line%1: Bad SOUND statement."
        CASE 148
            Var$ = "Error #148: Line%1: FN call error: %2."
        CASE 149
            Var$ = "Error #149: Line%1: FZ call error: %2."
        CASE 150
            Var$ = "Error #150: Line%1: Bad exponent unary sign."
        CASE 151
            Var$ = "Error #151: Line%1: Bad exponent decimal point."
        CASE 154
            Var$ = "Error #154: Line%1: Bad SHELL call."
        CASE 155
            Var$ = "Error #155: Line%1: Restricted command."
        CASE 156
            Var$ = "Error #156: Line%1: Maximum nested gosub."
        CASE 157
            Var$ = "Error #157: Line%1: Square root of a negative value."
        CASE 158
            Var$ = "Error #158: Line%1: Unknown INT86 function."
        CASE 159
            Var$ = "Error #159: Line%1: Feature not available."
        CASE 160
            Var$ = "Error #160: Line%1: Unknown metacommand."
        CASE 161
            Var$ = "Error #161: Line%1: Illegal line printer function."
        CASE 162
            Var$ = "Error #162: Line%1: Illegal MID$ function call."
        CASE 163
            Var$ = "Error #163: Line%1: Illegal LEFT$ function call."
        CASE 164
            Var$ = "Error #164: Line%1: Illegal RIGHT$ function call."
        CASE 165
            Var$ = "Error #165: Line%1: Illegal ENVIRON$ function call."
        CASE 166
            Var$ = "Error #166: Line%1: Drive not available."
        CASE 167
            Var$ = "Error #167: Line%1: Illegal write function."
        CASE 168
            Var$ = "Error #168: Line%1: Invalid TRIANGLE statement."
        CASE 169
            Var$ = "Error #169: Line%1: Invalid POLYGON statement."
        CASE 79, 90, 93 TO 96, 106 TO 109, 152, 153, 170 TO 255
            Var$ = "User defined error #" + MID$(STR$(ErrorValue), 2) + ": Line%1."
        CASE ELSE ' unknown error
            Var$ = "Error #000: Error: Line%1."
    END SELECT

    ' parse out ': Line%1:'
    Parse = INSTR(Var$, "%1")
    IF Parse THEN
        ' check error line number
        IF ErrorLine = False THEN ' remove %1 string
            Var$ = LEFT$(Var$, Parse - 7) + MID$(Var$, Parse + 2)
        ELSE ' replace %1 string
            Var$ = LEFT$(Var$, Parse - 1) + STR$(ErrorLine) + MID$(Var$, Parse + 2)
        END IF
    END IF
    ' parse out ': %2.'
    Parse = INSTR(Var$, "%2")
    IF Parse THEN
        ' check token string
        IF Strng = CHR$(9) THEN
            Strng = "<tab>"
        END IF
        IF LEN(Strng) = False THEN ' remove %2 string
            Var$ = LEFT$(Var$, Parse - 1) + "<?>" + MID$(Var$, Parse + 2)
        ELSE ' replace %2 string
            Var$ = LEFT$(Var$, Parse - 1) + Strng + MID$(Var$, Parse + 2)
        END IF
    END IF
    PRINT RTRIM$(Var$)
END SUB

' parses and stores a program line number
SUB EnterProgramLine
    Assign = False
    Out2 = STRIM$(Out2)
    FOR Blanks = 1 TO LEN(Out2)
        Imbedded = False
        FOR Parse = 1 TO LEN(WhiteSpace)
            IF MID$(Out2, Blanks, 1) = MID$(WhiteSpace, Parse, 1) THEN
                Imbedded = Blanks
                EXIT FOR
            END IF
        NEXT
        IF Imbedded THEN
            LineNumber = INT(VAL(LEFT$(Out2, Imbedded - 1)))
            IF LineNumber >= 1 AND LineNumber <= MaxLines THEN
                Out3 = MID$(Out2, Imbedded)
                IF STRIM$(Out3) = Nul THEN
                    EXIT FOR
                END IF
                Assign = True
                Program$(LineNumber) = Out3
                IF ProgramName = None THEN
                    ProgramName = Untitled
                END IF
                IF AutoIndent THEN
                    CALL IndentProgram(-1, 3) ' autoindent
                END IF
            ELSE
                Out3 = STRIM$(Out2)
                IF INSTR("0123456789", LEFT$(Out3, 1)) THEN
                    Assign = True
                    PRINT "Line number out of range."
                END IF
            END IF
            EXIT SUB
        END IF
    NEXT
    LineNumber = INT(VAL(Out2))
    IF LineNumber > False AND LineNumber <= MaxLines THEN
        Assign = True
        Program$(LineNumber) = Nul
        CALL CountLines(LastLine)
        IF LastLine = False THEN
            ProgramName = None
        ELSE
            IF ProgramName = None THEN
                ProgramName = Untitled
            END IF
        END IF
        IF AutoIndent THEN
            CALL IndentProgram(-1, 3) ' autoindent
        END IF
    ELSE
        Out3 = STRIM$(Out2)
        IF INSTR("0123456789", LEFT$(Out3, 1)) THEN
            Assign = True
            PRINT "Line number out of range."
        END IF
    END IF
END SUB

' indents current program
SUB IndentProgram (Auto, NumberSpaces)
    CALL AnalyzeProgram(0, VarX, Var$)
    IF VarX THEN
        IF Auto THEN
            EXIT SUB
        END IF
        COLOR White
        PRINT "Program analyze error line:" + STR$(ProgramLine) + ": " + Var$ + "."
        EXIT SUB
    END IF
    IF Auto THEN
        Increment = AutoIndentSpaces
    ELSE
        Increment = INT(NumberSpaces)
        IF NumberSpaces = False THEN
            COLOR White, Black
            PRINT "Enter number of spaces to indent: ";
            LINE INPUT Var$
            Increment = INT(VAL(Var$))
        END IF
    END IF
    IF Increment <= 0 THEN
        EXIT SUB
    END IF
    Indent = False
    CALL CountLines(LastLine)
    MX = LEN(STR$(LastLine))
    FOR ProgramLine = 1 TO LastLine
        Number$ = SPACE$(MX - LEN(MID$(STR$(ProgramLine), 2)))
        Out2 = Program$(ProgramLine)
        Out2 = STRIM$(Out2)
        IF LEN(Out2) THEN
            Temp1$ = STRIM$(Out2)
            Temp1$ = UCASE$(Temp1$)
            Temp1$ = TTRIM$(Temp1$, False)
            NextIndent = False
            RESTORE IndentData
            DO
                READ Keyword$, KeyIndent
                IF Keyword$ = "EOF" THEN
                    EXIT DO
                END IF
                IF LEFT$(Temp1$, LEN(Keyword$)) = Keyword$ THEN
                    NextIndent = KeyIndent
                    EXIT DO
                END IF
            LOOP
            SELECT CASE NextIndent
                CASE 1 ' right
                    Out2 = SPACE$(Indent * Increment) + STRIM$(Out2)
                    Indent = Indent + 1
                CASE -1 ' left
                    Indent = Indent - 1
                    IF Indent < False THEN
                        IF Auto = 0 THEN
                            PRINT "Indent error: Line:"; ProgramLine
                        END IF
                        EXIT SUB
                    END IF
                    Out2 = SPACE$(Indent * Increment) + STRIM$(Out2)
                CASE -2 ' left/right
                    Indent = Indent - 1
                    IF Indent < False THEN
                        IF Auto = 0 THEN
                            PRINT "Indent error: Line:"; ProgramLine
                        END IF
                        EXIT SUB
                    END IF
                    Out2 = SPACE$(Indent * Increment) + STRIM$(Out2)
                    Indent = Indent + 1
                CASE ELSE
                    Out2 = SPACE$(Indent * Increment) + STRIM$(Out2)
            END SELECT
            Out2 = Number$ + Out2
            Program$(ProgramLine) = Out2
        END IF
    NEXT
    IF Auto THEN
        EXIT SUB
    END IF
    IF Indent <> False THEN
        PRINT "Indent error: Line:"; ProgramLine
        EXIT SUB
    END IF
    PRINT "Program indented."
END SUB

' deletes a .sic file
SUB DeleteProgram (Var$)
    DO
        IF Var$ = Nul THEN
            COLOR White, Black
            PRINT "Program name to kill: ";
            LINE INPUT ProgramFile$
        ELSE
            ProgramFile$ = Var$
        END IF
        IF LEN(ProgramFile$) = False THEN
            EXIT DO
        END IF
        Filename = ProgramFile$
        IF _FILEEXISTS(Filename) = 0 THEN
            PRINT "File " + Quote + Filename + Quote + " does not exist."
            IF LEN(Var$) THEN
                EXIT DO
            END IF
        ELSE
            IF Var$ = Nul THEN
                COLOR White, Black
                PRINT "Kill " + Quote + Filename + Quote + "."
                CALL MorePrompt("Are you sure(y/n)?", "yn", OutputChar$)
            ELSE
                OutputChar$ = "y"
            END IF
            COLOR White, Black
            IF OutputChar$ = "y" THEN
                KILL Filename
                PRINT "Program " + Quote + Filename + Quote + " killed."
            ELSE
                PRINT "Program " + Quote + Filename + Quote + " not killed."
            END IF
            EXIT DO
        END IF
    LOOP
END SUB

' display dirs/files
'   VarQ = 0 for directories only
SUB ListFiles (VarZ$, VarQ)
    DIM ASCIIZ4 AS STRING * 260

    IF LINUX OR MACOSX THEN
        ERROR 73
        EXIT SUB
    END IF

    ErrorCount = 0
    ErrorType2 = -1

    ' reset search parameter
    IF LEN(VarZ$) THEN
        Var4$ = VarZ$
    ELSE
        Var4$ = "*.sic"
    END IF

    ' display header
    COLOR White, Black
    PRINT "Searching: " + Var4$
    GOSUB TitleHeader

    c = 0
    q = 0
    v = 1
    t = 0
    FOR l = 1 TO 2 ' dirs/files
        IF l = 2 THEN
            IF VarQ = 0 THEN
                EXIT FOR
            END IF
        END IF
        ASCIIZ4 = Var4$ + CHR$(0)
        hfind = FindFirstFileA(_OFFSET(ASCIIZ4), _OFFSET(finddata))
        IF hfind <> INVALID_HANDLE_VALUE THEN
            z = 0
            DO
                OK = 0
                Var# = finddata.dwFileAttributes
                IF l = 1 THEN
                    IF (Var# AND &H10) = &H10 THEN
                        OK = -1
                    END IF
                END IF
                IF l = 2 THEN
                    IF (Var# AND &H10) = &H0 THEN
                        OK = -1
                    END IF
                END IF

                X$ = finddata.cFileName
                VarX = INSTR(X$, CHR$(0))
                IF VarX THEN
                    X$ = LEFT$(X$, VarX - 1)
                END IF
                X$ = RTRIM$(X$)
                IF X$ = "." OR X$ = ".." THEN
                    OK = 0
                END IF
                IF OK THEN
                    IF t THEN
                        t = 0
                        GOSUB TitleHeader
                    END IF
                    Attr$ = SPACE$(7)
                    IF l = 1 THEN
                        MID$(Attr$, 2, 1) = "D"
                        d1 = d1 + 1
                    ELSE
                        f1 = f1 + 1
                    END IF
                    q = -1

                    ' print shortfilename
                    z$ = finddata.cAlternateFileName
                    vx = INSTR(z$, CHR$(0))
                    IF vx THEN
                        z$ = LEFT$(z$, vx - 1)
                    END IF
                    IF z$ = Nul THEN
                        z$ = finddata.cFileName
                        vx = INSTR(z$, CHR$(0))
                        IF vx THEN
                            z$ = LEFT$(z$, vx - 1)
                        END IF
                    END IF
                    IF LEN(z$) > 12 THEN
                        z$ = LEFT$(z$, 12)
                    END IF
                    COLOR Yellow, Black
                    PRINT UCASE$(z$);
                    IF LEN(z$) <= 14 THEN
                        PRINT SPACE$(14 - LEN(z$));
                    END IF

                    ' print date/time
                    x& = FileTimeToSystemTime&(finddata.ftLastWriteTime, SysTime)
                    Var$ = RIGHT$("00" + LTRIM$(STR$(SysTime.wMonth)), 2) + "-"
                    Var$ = Var$ + RIGHT$("00" + LTRIM$(STR$(SysTime.wDay)), 2) + "-"
                    Var$ = Var$ + LTRIM$(STR$(SysTime.wYear)) + "  "
                    Var$ = Var$ + RIGHT$("00" + LTRIM$(STR$(SysTime.wMonth)), 2) + "-"
                    Var$ = Var$ + RIGHT$("00" + LTRIM$(STR$(SysTime.wDay)), 2) + "-"
                    Var$ = Var$ + LTRIM$(STR$(SysTime.wYear))
                    COLOR Green, Black
                    PRINT Var$;

                    ' attributes of directory/filename
                    Var# = finddata.dwFileAttributes
                    IF Var# < 0 THEN
                        Var# = 0
                    END IF
                    IF (Var# AND &H20) = &H20 THEN
                        MID$(Attr$, 1, 1) = "A" ' archive
                    END IF
                    IF (Var# AND &H4) = &H4 THEN
                        MID$(Attr$, 3, 1) = "S" ' system
                    END IF
                    IF (Var# AND &H2) = &H2 THEN
                        MID$(Attr$, 4, 1) = "H" ' hidden
                    END IF
                    IF (Var# AND &H1) = &H1 THEN
                        MID$(Attr$, 5, 1) = "R" ' read-only
                    END IF
                    IF (Var# AND &H800) = &H800 THEN
                        MID$(Attr$, 6, 1) = "C" ' compressed
                    END IF
                    IF (Var# AND &H4000) = &H4000 THEN
                        MID$(Attr$, 7, 1) = "E" ' encrypted
                    END IF
                    COLOR Red, Black
                    PRINT " "; Attr$; " ";

                    ' print filesize
                    z$ = "<DIR>"
                    IF l = 2 THEN
                        Var# = finddata.nFileSizeHigh * &H100000000~&&
                        Var# = Var# OR finddata.nFileSizeLow
                        VarX# = VarX# + Var# ' add bytes
                        CALL Suffix(Var#, z$) ' 1,024.0 KB
                    END IF
                    z$ = LEFT$(z$, 10)
                    z$ = SPACE$(10 - LEN(z$)) + z$
                    COLOR Cyan, Black
                    PRINT z$; " ";

                    ' print longfilename
                    z$ = finddata.cFileName
                    VarX = INSTR(z$, CHR$(0))
                    IF VarX THEN
                        z$ = LEFT$(z$, VarX - 1)
                    END IF
                    z$ = RTRIM$(z$)
                    IF LEN(z$) THEN
                        IF LEN(z$) > 21 THEN
                            z$ = LEFT$(z$, 20) + "..."
                        END IF
                        COLOR Yellow, Black
                        PRINT z$;
                    END IF
                    PRINT

                    ' prompt
                    v = v + 1
                    IF v = 21 THEN
                        v = 0
                        IF c = 0 THEN
                            COLOR White, Black
                            PRINT MorePrompt4;
                            X$ = Nul
                            DO
                                _LIMIT 50
                                X$ = INKEY$
                                IF LEN(X$) THEN
                                    SELECT CASE LCASE$(X$)
                                        CASE "c" ' continuous
                                            c = -1
                                            EXIT DO
                                        CASE "n", "q" ' no/quit
                                            v = 0
                                            PRINT
                                            EXIT FOR
                                        CASE " ", CHR$(13), "y" ' yes/continue
                                            EXIT DO
                                    END SELECT
                                END IF
                            LOOP
                            PRINT
                            t = -1
                        END IF
                    END IF
                END IF
            LOOP WHILE FindNextFileA(hfind, _OFFSET(finddata))
            x = FindClose(hfind)
        END IF
    NEXT
    IF q = 0 THEN
        COLOR Yellow, Black
        PRINT None
    END IF

    ' print totals
    COLOR White, Black
    PRINT "------------                                 ----------"
    TotalLine$ = "Files " + FormatString$(CDBL(f1))
    TotalLine$ = TotalLine$ + " Dirs " + FormatString$(CDBL(d1))
    TotalLine$ = LEFT$(TotalLine$, 40)
    TotalLine$ = TotalLine$ + SPACE$(44 - LEN(TotalLine$))

    CALL Suffix(VarX#, z$) ' 1,024.0 KB
    TotalLine$ = TotalLine$ + SPACE$(11 - LEN(z$)) + z$
    PRINT TotalLine$
    EXIT SUB

    TitleHeader:
    COLOR White, Black
    PRINT "Filename      Date        Time       Attr          Size Longfilename"
    PRINT "------------  ----------  --------   -----   ---------- ------------"
    RETURN
END SUB

' lists specified drives
SUB ListDrives (Var$, VarQ)
    ' Var$ = "x..." only list drives in string
    ' VarQ = 0 list all drives, VarQ = 1 to 26 list drives in array list
    '    always skips A: and B: unless array element 1 or 2 is equal to 1.

    IF LINUX OR MACOSX THEN
        ERROR 73
        EXIT SUB
    END IF

    l = 0
    GOSUB DriveHeader
    FOR c = 1 TO 26
        IF Var$ <> Nul THEN ' display specific drives
            x$ = UCASE$(Var$)
            IF INSTR(x$, CHR$(c + 64)) THEN
                x = INSTR(x$, CHR$(c + 64))
                x = ASC(MID$(x$, x, 1))
                IF x >= 65 AND x <= 90 THEN
                    x = x - 64
                    IF c = x THEN
                        GOSUB DisplayDrive
                    END IF
                END IF
            END IF
        ELSE
            IF VarQ = 0 THEN ' display all drives except A: or B:
                IF c >= 3 THEN
                    GOSUB DisplayDrive
                END IF
            ELSE
                IF c <= 2 THEN ' check floppy override
                    IF Arrays(VarQ, c) = 1 THEN
                        GOSUB DisplayDrive
                    END IF
                ELSE
                    IF Arrays(VarQ, c) = 0 THEN ' compare drive array list
                        GOSUB DisplayDrive
                    END IF
                END IF
            END IF
        END IF
        IF h = 20 THEN
            h = 0
            CALL MorePrompt(MorePrompt4, "y " + CHR$(13), Output.Char$)
            GOSUB DriveHeader
        END IF
    NEXT
    IF q = 0 THEN
        PRINT "<none>"
    ELSE
        COLOR White, Black
        PRINT "Total drives"; l
    END IF
    EXIT SUB

    DisplayDrive:
    c$ = CHR$(c + 64)
    Out3 = c$
    IF DRIVEEXISTS(c) = 0 THEN
        h = h + 1
        l = l + 1
        q = -1

        ' display drive letter
        COLOR White, Black
        PRINT c$; ":    ";

        ' display volume label
        COLOR Yellow, Black
        Out3 = c$
        CALL Vlabel(Out3)
        IF RTRIM$(Out3) = "" THEN
            z$ = DriveType
        ELSE
            z$ = LEFT$(Out3, 12)
        END IF
        z$ = z$ + SPACE$(13 - LEN(z$))
        PRINT z$;

        ' display volume serial number
        COLOR Green, Black
        Out3 = c$
        CALL Vserial(Out3)
        z$ = LEFT$(Out3, 12)
        z$ = z$ + SPACE$(13 - LEN(z$))
        PRINT z$;

        ' display volume file system type
        COLOR Red, Black
        Out3 = c$
        CALL Vtype(Out3)
        z$ = LEFT$(Out3, 8)
        z$ = z$ + SPACE$(9 - LEN(z$))
        PRINT z$;

        ' display volume total disk space
        COLOR Cyan, Black
        Out3 = c$
        CALL TotalSpace(Out3)
        x# = INT(VAL(Out3))
        x1# = x#
        IF x# > 0# THEN
            CALL Suffix(x#, S$) ' 1,024.0 KB
            PRINT SPACE$(11 - LEN(S$)) + S$;
        ELSE
            PRINT "      <n/a>";
        END IF

        ' display volume free disk space
        Out3 = c$
        CALL FreeSpace(Out3)
        y# = INT(VAL(Out3))
        y1# = y#
        IF y# > 0# THEN
            CALL Suffix(y#, S$) ' 1,024.0 KB
            PRINT SPACE$(11 - LEN(S$)) + S$;
        ELSE
            PRINT "      <n/a>";
        END IF

        ' display volume used disk space
        IF x1# > 0# OR y1# > 0# THEN
            z# = x1# - y1#
            CALL Suffix(z#, S$) ' 1,024.0 KB
            PRINT SPACE$(11 - LEN(S$)) + S$
        ELSE
            PRINT "      <n/a>"
        END IF
    END IF
    RETURN

    DriveHeader:
    h = 2
    COLOR White, Black
    PRINT "Drive Label        Serial       Type           Total       Free       Used"
    PRINT "--------------------------------------------------------------------------"
    RETURN
END SUB

' formats a double numeric string
FUNCTION FormatString$ (s#)
    x$ = Nul
    s$ = STR$(s#)
    IF INSTR(s$, "D") THEN ' return string
        FormatString$ = s$
        EXIT FUNCTION
    END IF
    IF LEFT$(s$, 1) = "-" THEN ' store sign
        e$ = "-"
        s$ = MID$(s$, 2)
    END IF
    s$ = LTRIM$(s$) ' format string
    IF INSTR(s$, ".") THEN
        q$ = MID$(s$, INSTR(s$, "."))
        s$ = LEFT$(s$, INSTR(s$, ".") - 1)
    END IF
    FOR l = LEN(s$) TO 3 STEP -3
        x$ = MID$(s$, l - 2, 3) + "," + x$
    NEXT
    IF l > 0 THEN
        x$ = MID$(s$, 1, l) + "," + x$
    END IF
    IF LEN(s$) < 3 THEN
        x$ = s$
    END IF
    IF RIGHT$(x$, 1) = "," THEN
        x$ = LEFT$(x$, LEN(x$) - 1)
    END IF
    x$ = e$ + x$ + q$ ' construct string
    FormatString$ = x$
END FUNCTION

' ambiguate function
FUNCTION Ambiguate$ (Var$)
    DIM ASCIIZ4 AS STRING * 260
    DIM ASCIIZ5 AS STRING * 260

    IF LEN(Var$) = 0 THEN
        Ambiguate$ = Nul
        EXIT FUNCTION
    END IF

    IF LINUX OR MACOSX THEN
        Ambiguate$ = Nul
        EXIT FUNCTION
    END IF

    ASCIIZ4 = Var$ + CHR$(0)
    ret = GetShortPathName(ASCIIZ4, ASCIIZ5, MAX_PATH + 1)
    IF ret > 0 THEN
        Var2$ = ASCIIZ5
    ELSE
        Var2$ = ASCIIZ4
    END IF
    v = INSTR(Var2$, CHR$(0))
    IF v THEN
        Var2$ = LEFT$(Var2$, v - 1)
    END IF
    IF Var2$ = "." THEN
        Var2$ = Nul
    END IF
    Ambiguate$ = Var2$
END FUNCTION

' emulate shortfilename DIR$()
SUB FileDir (Var3$)
    DIM ASCIIZ4 AS STRING * 260

    IF LINUX OR MACOSX THEN
        Out3 = Nul
        EXIT SUB
    END IF

    ' init filelist
    IF LEN(Var3$) THEN
        ' see if directory exists
        Var4$ = Var3$
        IF _DIREXISTS(Var3$) THEN
            IF RIGHT$(Var3$, 1) = "\" THEN
                Var4$ = Var4$ + "*.*"
            ELSE
                Var4$ = Var4$ + "\*.*"
            END IF
        END IF

        IF hfind2 THEN
            x = FindClose(hfind2)
            hfind2 = 0
        END IF

        ASCIIZ4 = Var4$ + CHR$(0)
        hfind2 = FindFirstFileA(_OFFSET(ASCIIZ4), _OFFSET(finddata2))
        IF hfind2 = INVALID_HANDLE_VALUE THEN
            hfind2 = 0
            Out3 = Nul
            EXIT SUB
        END IF
    END IF

    ' get short filename
    IF hfind2 THEN
        Out3 = finddata2.cAlternateFileName
        VarX = INSTR(Out3, CHR$(0))
        IF VarX THEN
            Out3 = LEFT$(Out3, VarX - 1)
        END IF
        IF Out3 = Nul THEN
            Out3 = finddata2.cFileName
            VarX = INSTR(Out3, CHR$(0))
            IF VarX THEN
                Out3 = LEFT$(Out3, VarX - 1)
            END IF
        END IF
        Out3 = RTRIM$(Out3)
        Out3 = UCASE$(Out3)
        IF FindNextFileA(hfind2, _OFFSET(finddata2)) = 0 THEN
            x = FindClose(hfind2)
            hfind2 = 0
        END IF
    END IF
END SUB

' emulate longfilename DIRX$()
SUB FileDirX (Var3$)
    DIM ASCIIZ4 AS STRING * 260

    IF LINUX OR MACOSX THEN
        Out3 = Nul
        EXIT SUB
    END IF

    ' init filelist
    IF LEN(Var3$) THEN
        ' see if directory exists
        Var4$ = Var3$
        IF _DIREXISTS(Var3$) THEN
            IF RIGHT$(Var3$, 1) = "\" THEN
                Var4$ = Var4$ + "*.*"
            ELSE
                Var4$ = Var4$ + "\*.*"
            END IF
        END IF

        IF hfind3 THEN
            x = FindClose(hfind3)
            hfind3 = 0
        END IF

        ASCIIZ4 = Var4$ + CHR$(0)
        hfind3 = FindFirstFileA(_OFFSET(ASCIIZ4), _OFFSET(finddata3))
        IF hfind3 = INVALID_HANDLE_VALUE THEN
            hfind3 = 0
            Out3 = Nul
            EXIT SUB
        END IF
    END IF

    ' get long filename
    IF hfind3 THEN
        Out3 = finddata3.cFileName
        VarX = INSTR(Out3, CHR$(0))
        IF VarX THEN
            Out3 = LEFT$(Out3, VarX - 1)
        END IF
        Out3 = RTRIM$(Out3)
        IF FindNextFileA(hfind3, _OFFSET(finddata3)) = 0 THEN
            x = FindClose(hfind3)
            hfind3 = 0
        END IF
    END IF
END SUB

' check drive exists.
'  returns -1 if drive not detected.
FUNCTION DRIVEEXISTS (V)
    VarX$ = CHR$(V + 64) + ":\" + CHR$(0)
    VarX = GetDriveType(VarX$)
    DriveType = ""
    SELECT CASE VarX
        CASE 0
            DriveType = "[UNKNOWN]"
        CASE 1
            DriveType = "[BADROOT]"
        CASE 2
            DriveType = "[REMOVABLE]"
        CASE 3
            DriveType = "[FIXED]"
        CASE 4
            DriveType = "[REMOTE]"
        CASE 5
            DriveType = "[CDROM]"
        CASE 6
            DriveType = "[RAMDISK]"
    END SELECT
    IF VarX > 1 THEN
        DRIVEEXISTS = 0
    ELSE
        DRIVEEXISTS = -1
    END IF
END FUNCTION

' check netpath exists.
'  returns -1 if netpath not detected.
FUNCTION NETPATHEXISTS (Z$)
    VarX$ = Z$ + CHR$(0)
    VarX = GetDriveType(VarX$)
    IF VarX > 1 THEN
        NETPATHEXISTS = 0
    ELSE
        NETPATHEXISTS = -1
    END IF
END FUNCTION

' get current directory.
FUNCTION CurDir$
    F$ = SPACE$(MAX_PATH)
    R = GetModuleFileNameA(0, F$, LEN(F$))
    IF R THEN
        F$ = LEFT$(F$, R)
        VarX = INSTR(F$, CHR$(0))
        IF VarX THEN
            F$ = LEFT$(F$, VarX - 1)
        END IF
        CurDir$ = RTRIM$(F$)
        FOR s = LEN(CurDir$) TO 1 STEP -1
            IF MID$(CurDir$, s, 1) = "\" THEN
                CurDir$ = LEFT$(CurDir$, s - 1)
                EXIT FOR
            END IF
        NEXT
        IF RIGHT$(CurDir$, 1) <> "\" THEN
            IF LEN(CurDir$) = 2 THEN
                CurDir$ = CurDir$ + "\"
            END IF
        END IF
        EXIT FUNCTION
    END IF
    CurDir$ = "C:\"
END FUNCTION

' get file date
SUB FileDate (Var$)
    DIM ASCIIZ4 AS STRING * 260

    IF LINUX OR MACOSX THEN
        Var$ = Nul
        EXIT SUB
    END IF

    IF Var$ = Nul THEN
        ERROR 53
        EXIT SUB
    END IF

    IF INSTR(Var$, "?") OR INSTR(Var$, "*") THEN
        ERROR 53
        EXIT SUB
    END IF

    ErrorCount = 0
    ErrorType2 = -1

    ' construct file date for display.
    ASCIIZ4 = Var$ + CHR$(0)
    Var$ = Nul
    hfind = FindFirstFileA(_OFFSET(ASCIIZ4), _OFFSET(finddata))
    IF hfind <> INVALID_HANDLE_VALUE THEN
        x& = FileTimeToSystemTime&(finddata.ftLastWriteTime, SysTime)
        Var$ = RIGHT$("00" + LTRIM$(STR$(SysTime.wMonth)), 2) + "-"
        Var$ = Var$ + RIGHT$("00" + LTRIM$(STR$(SysTime.wDay)), 2) + "-"
        Var$ = Var$ + LTRIM$(STR$(SysTime.wYear))
        x = FindClose(hfind)
    END IF
END SUB

' get file time
SUB FileTime (Var$)
    DIM ASCIIZ4 AS STRING * 260

    IF LINUX OR MACOSX THEN
        Var$ = Nul
        EXIT SUB
    END IF

    IF Var$ = Nul THEN
        ERROR 53
        EXIT SUB
    END IF

    IF INSTR(Var$, "?") OR INSTR(Var$, "*") THEN
        ERROR 53
        EXIT SUB
    END IF

    ErrorCount = 0
    ErrorType2 = -1

    ' construct file time for display.
    ASCIIZ4 = Var$ + CHR$(0)
    Var$ = Nul
    hfind = FindFirstFileA(_OFFSET(ASCIIZ4), _OFFSET(finddata))
    IF hfind <> INVALID_HANDLE_VALUE THEN
        x& = FileTimeToSystemTime&(finddata.ftLastWriteTime, SysTime)
        Var$ = RIGHT$("00" + LTRIM$(STR$(SysTime.wHour)), 2) + ":"
        Var$ = Var$ + RIGHT$("00" + LTRIM$(STR$(SysTime.wMinute)), 2) + ":"
        Var$ = Var$ + RIGHT$("00" + LTRIM$(STR$(SysTime.wSecond)), 2)
        x = FindClose(hfind)
    END IF
END SUB

' get file size
SUB FileSize (Var#)
    DIM ASCIIZ4 AS STRING * 260

    IF LINUX OR MACOSX THEN
        Var# = 0#
        EXIT SUB
    END IF

    IF Out3 = Nul THEN
        ERROR 53
        EXIT SUB
    END IF

    IF INSTR(Out3, "?") OR INSTR(Out3, "*") THEN
        ERROR 53
        EXIT SUB
    END IF

    ErrorCount = 0
    ErrorType2 = -1

    ' get file size.
    ASCIIZ4 = Out3 + CHR$(0)
    Var# = 0#
    hfind = FindFirstFileA(_OFFSET(ASCIIZ4), _OFFSET(finddata))
    IF hfind <> INVALID_HANDLE_VALUE THEN
        x& = FileTimeToSystemTime&(finddata.ftLastWriteTime, SysTime)
        Var# = finddata.nFileSizeHigh * &H100000000~&& OR finddata.nFileSizeLow
        x = FindClose(hfind)
    END IF
END SUB

' get dir/file attribute
SUB FileAttr (Var#)
    DIM ASCIIZ4 AS STRING * 260

    IF LINUX OR MACOSX THEN
        Var# = 0#
        EXIT SUB
    END IF

    IF Out3 = Nul THEN
        ERROR 53
        EXIT SUB
    END IF

    IF INSTR(Out3, "?") OR INSTR(Out3, "*") THEN
        ERROR 53
        EXIT SUB
    END IF

    ErrorCount = 0
    ErrorType2 = -1

    ASCIIZ4 = Out3 + CHR$(0)
    Var# = GetFileAttributes(ASCIIZ4)
    IF Var# < 0 THEN
        Var# = 0
    END IF
END SUB

' get volume label
SUB Vlabel (Var$)
    IF LINUX OR MACOSX THEN
        Var$ = Nul
        EXIT SUB
    END IF

    ' get drive info.
    VarX$ = Var$ + ":\" + CHR$(0)
    Var$ = Nul
    Vname$ = SPACE$(MAX_PATH)
    Fname$ = SPACE$(MAX_PATH)
    R = GetVolumeInformationA(VarX$, Vname$, MAX_PATH, serial~&, empty1~&, empty2~&, Fname$, MAX_PATH)
    IF R THEN
        ' get volume label.
        Var$ = RTRIM$(Vname$)
        v = INSTR(Var$, CHR$(0))
        IF v THEN Var$ = LEFT$(Var$, v - 1)
    END IF
END SUB

' get volume serial number
SUB Vserial (Var$)
    IF LINUX OR MACOSX THEN
        Var$ = Nul
        EXIT SUB
    END IF

    ' get drive info.
    VarX$ = Var$ + ":\" + CHR$(0)
    Var$ = Nul
    Vname$ = SPACE$(MAX_PATH)
    Fname$ = SPACE$(MAX_PATH)
    R = GetVolumeInformationA(VarX$, Vname$, MAX_PATH, serial~&, empty1~&, empty2~&, Fname$, MAX_PATH)
    IF R THEN
        ' serial number.
        Var$ = LEFT$(HEX$(serial~&), 4) + "-" + RIGHT$(HEX$(serial~&), 4)
    END IF
END SUB

' get volume system type
SUB Vtype (Var$)
    IF LINUX OR MACOSX THEN
        Var$ = Nul
        EXIT SUB
    END IF

    ' get drive info.
    VarX$ = Var$ + ":\" + CHR$(0)
    Var$ = Nul
    Vname$ = SPACE$(MAX_PATH)
    Fname$ = SPACE$(MAX_PATH)
    R = GetVolumeInformationA(VarX$, Vname$, MAX_PATH, serial~&, empty1~&, empty2~&, Fname$, MAX_PATH)
    IF R THEN
        ' get volume system type.
        Var$ = RTRIM$(Fname$)
        v = INSTR(Var$, CHR$(0))
        IF v THEN Var$ = LEFT$(Var$, v - 1)
    END IF
END SUB

' get drive freespace
SUB FreeSpace (Var$)
    IF LINUX OR MACOSX THEN
        Var$ = Nul
        EXIT SUB
    END IF

    VarX$ = Var$ + ":\" + CHR$(0)
    Var$ = Nul
    c = ASC(LEFT$(VarX$, 1)) - 64
    IF DRIVEEXISTS(c) THEN
        EXIT SUB
    END IF
    IF DriveType = "[CDROM]" THEN
        EXIT SUB
    END IF
    IF DriveType = "[REMOVABLE]" THEN
        EXIT SUB
    END IF
    r = GetDiskFreeSpaceExA(VarX$, free~&&, total~&&, free2~&&)
    IF r THEN
        Var$ = LTRIM$(STR$(free~&&))
    END IF
    EXIT SUB

    r = GetDiskFreeSpaceA(VarX$, sectors&, bytes&, free&, total&)
    IF r THEN
        ' sectors per cluster * bytes per sector * free clusters
        x1# = CDBL(sectors&) * CDBL(bytes&) * CDBL(free&)
        Var$ = LTRIM$(STR$(x1#))
    END IF
END SUB

' get drive totalspace
SUB TotalSpace (Var$)
    IF LINUX OR MACOSX THEN
        Var$ = Nul
        EXIT SUB
    END IF

    VarX$ = Var$ + ":\" + CHR$(0)
    Var$ = Nul
    c = ASC(LEFT$(VarX$, 1)) - 64
    IF DRIVEEXISTS(c) THEN
        EXIT SUB
    END IF
    IF DriveType = "[CDROM]" THEN
        EXIT SUB
    END IF
    IF DriveType = "[REMOVABLE]" THEN
        EXIT SUB
    END IF
    r = GetDiskFreeSpaceExA(VarX$, free~&&, total~&&, free2~&&)
    IF r THEN
        Var$ = LTRIM$(STR$(total~&&))
    END IF
    EXIT SUB

    r = GetDiskFreeSpaceA(VarX$, sectors&, bytes&, free&, total&)
    IF r THEN
        ' sectors per cluster * bytes per sector * total clusters
        x1# = CDBL(sectors&) * CDBL(bytes&) * CDBL(total&)
        Var$ = LTRIM$(STR$(x1#))
    END IF
END SUB

' display help menu
SUB ListHelp
    DO
        COLOR White, Black
        PRINT "Help utility SIC64 v" + Version + " r" + Release + " list: for QB64:"
        COLOR Yellow, Black
        PRINT "[1]command list"
        PRINT "[2]general documentation"
        PRINT "[3]formatting information"
        PRINT "[4]screen mode tables"
        PRINT "[5]error code values"
        PRINT "[6]syntax documentation"
        PRINT "[7]boolean syntax/charts"
        PRINT "[8]troolean syntax/charts"
        PRINT "[9]disclaimer notice"
        PRINT "[A]shareware information"
        CALL MorePrompt("Enter(1-A,Q to quit)?", "123456789aq", OutputChar$)
        SELECT CASE OutputChar$
            CASE "1"
                COLOR White, Black
                PRINT "SIC64 created: " + PublishDate
                COLOR Yellow, Black
                PRINT "ANALYZE  --  checks program structure."
                PRINT "AUTOINDENT  --  toggles autoindent."
                PRINT "CONTINUE --  continue halted program."
                PRINT "DEBUG    --  immediate debug mode."
                PRINT "DIRS     --  list directories."
                PRINT "DRIVES   --  list drive labels/space."
                PRINT "FILES    --  list filenames."
                PRINT "HELP     --  lists help topics."
                PRINT "INDENT   --  formats current program."
                PRINT "KILL     --  delete program."
                PRINT "LIST     --  display current program."
                PRINT "LOAD     --  read program from disk."
                PRINT "NEW      --  erase current program."
                PRINT "PRINT    --  print current program."
                PRINT "QUIT     --  exit SIC64 interpreter."
                CALL KeyPrompt
                COLOR Yellow, Black
                PRINT "RENUMBER --  renumber program."
                PRINT "RUN      --  start current program."
                PRINT "SAVE     --  store current program."
                PRINT "SEARCH   --  search program for keyword."
                PRINT "SET      --  set string display for prompts."
                PRINT "SHELL    --  exit to dos shell."
                PRINT "VERSION  --  displays program version."
                PRINT "WHATIS   --  enter immediate mode."
                CALL KeyPrompt
            CASE "2"
                Filename = "sic64.doc"
                CALL ListHelpFile
            CASE "3"
                Filename = "sicform.doc"
                CALL ListHelpFile
            CASE "4"
                Filename = "sicscrn.doc"
                CALL ListHelpFile
            CASE "5"
                Filename = "error.doc"
                CALL ListHelpFile
            CASE "6"
                Filename = "syntax.doc"
                CALL ListHelpFile
            CASE "7"
                Filename = "boolean.doc"
                CALL ListHelpFile
            CASE "8"
                Filename = "troolean.doc"
                CALL ListHelpFile
            CASE "9"
                Filename = "disclaim.doc"
                CALL ListHelpFile
            CASE "a"
                Filename = "disclam2.doc"
                CALL ListHelpFile
            CASE "q"
                EXIT DO
        END SELECT
    LOOP
END SUB

' displays a help file
SUB ListHelpFile
    FileFound = _FILEEXISTS(Filename$)
    IF FileFound = False THEN
        PRINT "Helpfile " + Quote + Filename + Quote + " not found."
        PRINT "Set environment path variable to point at SIC64 files."
        CALL MorePrompt(MorePrompt1, "ync", OutputChar$)
        EXIT SUB
    END IF
    X = FreeFileNumber
    OPEN Filename$ FOR INPUT AS #FileNumber
    Continuous = False
    LineCount = False
    DO WHILE NOT EOF(FileNumber)
        COLOR Yellow, Black
        LINE INPUT #FileNumber, InputLine$
        PRINT InputLine$
        IF Continuous = False THEN
            LineCount = LineCount + 1
            IF LineCount = PageLength THEN
                LineCount = False
                CALL MorePrompt(MorePrompt1, "ync" + CHR$(13), OutputChar$)
                SELECT CASE OutputChar$
                    CASE "n"
                        EXIT DO
                    CASE "c"
                        Continuous = True
                END SELECT
            END IF
        END IF
    LOOP
    CALL KeyPrompt
    CLOSE #FileNumber
    FileNumber = False
END SUB

' lists current .sic program
SUB ListProgram (StartLine, StopLine, PrintProg)
    COLOR White, Black
    IF PrintProg THEN
        CALL MorePrompt("Printer number(1-3,q)?", "123q", OutputChar$)
        IF OutputChar$ = "q" THEN
            EXIT SUB
        END IF
        PrintNumber = INT(VAL(OutputChar$))
        X = FreeFileNumber
        OPEN "LPT" + MID$(STR$(PrintNumber), 2) + ":" FOR OUTPUT AS #FileNumber
    END IF
    IF PrintProg THEN
        PRINT #FileNumber, "Program: "; ProgramName
    ELSE
        PRINT "Program: "; ProgramName
    END IF
    Continuous = False
    LineCount = 1
    FOR ProgramLine = StartLine TO StopLine
        Out2 = Program$(ProgramLine)
        IF LEN(Out2) THEN
            COLOR Yellow, Black
            IF PrintProg THEN
                IF INSTR(WhiteSpace, LEFT$(Out2, 1)) THEN
                    PRINT #FileNumber, MID$(STR$(ProgramLine), 2) + Out2
                ELSE
                    PRINT #FileNumber, MID$(STR$(ProgramLine), 2) + " " + Out2
                END IF
            ELSE
                IF INSTR(WhiteSpace, LEFT$(Out2, 1)) THEN
                    V$ = ">" + MID$(STR$(ProgramLine), 2) + Out2
                ELSE
                    V$ = ">" + MID$(STR$(ProgramLine), 2) + " " + Out2
                END IF
                PRINT V$
                IF Continuous = False THEN
                    LineCount = LineCount + INT((LEN(V$) - 1) / 80) + 1
                    IF LineCount >= PageLength THEN
                        LineCount = False
                        CALL MorePrompt(MorePrompt1, "ync" + CHR$(13), OutputChar$)
                        SELECT CASE OutputChar$
                            CASE "n"
                                EXIT FOR
                            CASE "c"
                                Continuous = True
                        END SELECT
                    END IF
                END IF
            END IF
        END IF
    NEXT
    COLOR White, Black
    PRINT "Program list ended."
    IF PrintProg THEN
        CLOSE #FileNumber
        FileNumber = False
    END IF
END SUB

' searchs current .sic program
SUB SearchProgram
    CALL CountLines(LastLine)
    COLOR White, Black
    IF LastSearchLine > False THEN
        CALL MorePrompt("Continue search(y/n)?", "yn", OutputChar$)
        IF OutputChar$ = "y" THEN
            Var1 = LastSearchCase
            Var1$ = LastSearchKeyword
            StartLine = LastSearchLine + 1
            IF StartLine > MaxLines THEN
                COLOR White, Black
                PRINT "Program search ended."
                EXIT SUB
            END IF
            PRINT "Continuing search from line:" + STR$(StartLine)
            GOTO StartSearch
        END IF
    END IF
    DO
        ProgramLine = False
        Visible = 1
        COLOR Yellow, Black
        LOCATE , 1, 1
        PRINT "Search string?";
        LOCATE , , 1
        LINE INPUT Out2
        IF Out2 <> Nul THEN
            EXIT DO
        END IF
    LOOP
    Var1$ = Out2
    CALL MorePrompt("Case-sensitive(y/n)?", "yn", OutputChar$)
    IF OutputChar$ = "y" THEN
        Var1 = True
    ELSE
        Var1 = False
    END IF
    StartLine = 1

    StartSearch:

    PRINT "Searching Program: " + Quote + ProgramName + Quote

    FOR ProgramLine = StartLine TO LastLine
        Out2 = Program$(ProgramLine)
        IF LEN(Out2) THEN
            CALL InstrSUB1(Flag, Var1$, Out2, Var1)
            IF Flag THEN
                COLOR Yellow, Black
                IF INSTR(WhiteSpace, LEFT$(Out2, 1)) THEN
                    PRINT ">" + MID$(STR$(ProgramLine), 2) + Out2
                ELSE
                    PRINT ">" + MID$(STR$(ProgramLine), 2) + " " + Out2
                END IF
                CALL MorePrompt(MorePrompt2, "yn" + CHR$(13), OutputChar$)
                IF OutputChar$ = "n" THEN
                    EXIT FOR
                END IF
            END IF
        END IF
    NEXT
    LastSearchCase = Var1
    LastSearchLine = ProgramLine
    LastSearchKeyword = Var1$
    COLOR White, Black
    PRINT "Program search ended."
END SUB

' loads a .sic file
SUB LoadProgram (Var$)
    IF SaveOnExit THEN
        CALL SaveCurrent
    END IF
    IF _FILEEXISTS(PrepareFilename) THEN
        KILL PrepareFilename
    END IF
    IF Var$ = Nul THEN
        COLOR White, Black
        PRINT "Program name to load: ";
        LINE INPUT ProgramFile$
    ELSE
        ProgramFile$ = Var$
    END IF
    IF ProgramFile$ = Nul THEN
        EXIT SUB
    END IF
    CALL Concatenate(ProgramFile$)
    Filename = ProgramFile$
    LastSearchLine = False
    CALL NewProgram
    ProgramName = None
    CALL ReadProgram
    IF AutoIndent THEN
        CALL IndentProgram(-1, 3)
    END IF
    ProgramName = Filename
    COLOR White, Black
    PRINT "Program loaded."
END SUB

' prompts for a keystroke
SUB KeyPrompt
    IF BootError = False THEN
        COLOR White, Black
        LOCATE , , 1
        PRINT "Press any key to continue:";
        DO
            _LIMIT 50
            Var$ = INKEY$
            IF LEN(Var$) THEN
                EXIT DO
            END IF
        LOOP
        PRINT
    END IF
END SUB

' prompts for multiple input characters
SUB MorePrompt (InputString$, InputMask$, OutputString$)
    COLOR White, Black
    PRINT InputString$; " ";
    InputChar$ = Nul
    DO
        _LIMIT 50
        LOCATE , , 1
        InputChar$ = LCASE$(INKEY$)
        IF LEN(InputChar$) THEN
            IF INSTR(InputMask$, InputChar$) THEN
                IF InputChar$ = CHR$(13) THEN
                    PRINT
                ELSE
                    PRINT InputChar$
                END IF
                OutputString$ = InputChar$
                EXIT DO
            END IF
        END IF
    LOOP
END SUB

' remove current .sic program from memory
SUB NewProgram
    ' erase/redimension program code array
    REM ERASE Program$()
    REDIM Program(1 TO MaxLines) AS STRING
END SUB

' end of .sic program routine
SUB EndProgram
    CALL ResetScreen
    COLOR Plain, Black
    LOCATE , , , 8, 8
    IF LineFeed THEN
        IF POS(0) > 1 THEN
            PRINT
        END IF
    END IF
    InDEFSEG = False
END SUB

' quit the Sic64 program
SUB QuitProgram
    LineFeed = False
    IF SaveOnExit THEN
        CALL SaveCurrent
    END IF
    CALL KeyPrompt
    CALL EndProgram
    PRINT "Exiting to system.."
    CALL StopProgram
END SUB

' stop Sic64 program/exit to dos
SUB StopProgram

    ' Close/Kill files
    CLOSE
    IF _FILEEXISTS(PrepareFilename) THEN
        KILL PrepareFilename
    END IF
    IF _FILEEXISTS("SIC64.BAT") THEN
        KILL "SIC64.BAT"
    END IF

    ' exit program
    COLOR Plain, Black
    END
END SUB

' restore after any graphics screen modes
SUB ResetScreen
    IF LastScreen1 OR LastScreen2 OR LastScreen3 OR LastScreen4 THEN
        SCREEN 0, 1, 0, 0
        WIDTH 80, 25
    END IF
    IF LastWidth1 <> 80 THEN
        IF LastWidth2 <> 25 THEN
            WIDTH 80, 25
        END IF
    END IF
END SUB

' loads a program from disk
SUB ReadProgram
    X = FreeFileNumber
    IF _FILEEXISTS(Filename) THEN
        OPEN Filename FOR INPUT AS #FileNumber
        DO WHILE NOT EOF(FileNumber)
            LINE INPUT #FileNumber, Out2
            Out2 = STRIM$(Out2)
            FOR Blanks = 1 TO LEN(WhiteSpace)
                Imbedded = INSTR(Out2, MID$(WhiteSpace, Blanks, 1))
                IF Imbedded THEN
                    LineNumber = INT(VAL(LEFT$(Out2, Imbedded - 1)))
                    IF LineNumber > False AND LineNumber <= MaxLines THEN
                        Program$(LineNumber) = MID$(Out2, Imbedded)
                        EXIT FOR
                    END IF
                END IF
            NEXT
        LOOP
    END IF
    CLOSE #FileNumber
    FileNumber = False
END SUB

' renumbers current .sic program
SUB RenumberProgram (StartValue, IncrementValue)
    CALL AnalyzeProgram(0, VarX, Var$)
    IF VarX THEN
        COLOR White
        PRINT "Program analyze error line:" + STR$(ProgramLine) + ": " + Var$ + "."
        EXIT SUB
    END IF
    IF StartValue = False OR IncrementValue = False THEN
        COLOR White, Black
        PRINT "Starting line number: ";
        LINE INPUT Var$
        StartLine = INT(VAL(Var$))
        PRINT "Increment value: ";
        LINE INPUT Var$
        Increment = INT(VAL(Var$))
    ELSE
        StartLine = StartValue
        Increment = IncrementValue
    END IF
    StartLine = INT(StartLine)
    IF StartLine <= False THEN
        PRINT "Bad start line value."
        EXIT SUB
    END IF
    IF StartLine > MaxLines THEN
        PRINT "Bad start line value."
        EXIT SUB
    END IF
    Increment = INT(Increment)
    IF Increment <= False THEN
        PRINT "Bad increment value."
        EXIT SUB
    END IF
    IF Increment > INT(MaxLines / 2) THEN
        PRINT "Bad increment value."
        EXIT SUB
    END IF
    DO
        TempFilename$ = TempName$
        Filename = TempFilename$ + ".sc1"
        IF _FILEEXISTS(Filename) = 0 THEN
            EXIT DO
        END IF
    LOOP
    CALL StoreProgram
    CALL CountLines(LastLine)
    REDIM RenumberList(1 TO MaxLines) AS INTEGER
    NewLineNumber = StartLine
    FOR LineNumber = 1 TO LastLine
        ProgramLine$ = Program$(LineNumber)
        IF STRIM$(ProgramLine$) <> Nul THEN
            IF NewLineNumber > MaxLines THEN
                COLOR White, Black
                PRINT "Renumber list exceeds"; STR$(MaxLines); " lines."
                REM ERASE RenumberList
                EXIT SUB
            END IF
            RenumberList(NewLineNumber) = LineNumber
            NewLineNumber = NewLineNumber + Increment
        END IF
    NEXT
    PRINT "Renumbering program.."
    FOR LineNumber = 1 TO LastLine
        NewProgramLine$ = Program$(LineNumber)
        OldProgramLine$ = Program$(LineNumber)
        OldProgramLine$ = STRIM$(OldProgramLine$)
        OldProgramLine$ = TTRIM$(OldProgramLine$, True)
        IF OldProgramLine$ <> Nul THEN
            LineRenumbered = True
            IF UCASE$(LEFT$(OldProgramLine$, 7)) = "RESTORE" THEN
                V$ = RTRIM$(MID$(OldProgramLine$, 8))
                IF LEN(V$) THEN
                    IF INT(VAL(V$)) > 0 THEN
                        LineRenumbered = False
                        Imbedded = INSTR(UCASE$(NewProgramLine$), "RESTORE") + 7
                        GOSUB NextSpace
                        Number$ = MID$(OldProgramLine$, 8)
                        Number$ = STRIM$(Number$)
                        OldLineNumber = INT(VAL(Number$))
                        IF OldLineNumber > False AND OldLineNumber <= MaxLines THEN
                            FOR NewLineNumber = 1 TO MaxLines
                                IF RenumberList(NewLineNumber) = OldLineNumber THEN
                                    Program$(LineNumber) = NextProgramLine$ + LTRIM$(STR$(NewLineNumber))
                                    LineRenumbered = True
                                    EXIT FOR
                                END IF
                            NEXT
                        END IF
                    END IF
                END IF
            END IF
            IF UCASE$(LEFT$(OldProgramLine$, 4)) = "GOTO" THEN
                LineRenumbered = False
                Imbedded = INSTR(UCASE$(NewProgramLine$), "GOTO") + 4
                GOSUB NextSpace
                Number$ = MID$(OldProgramLine$, 5)
                Number$ = STRIM$(Number$)
                OldLineNumber = INT(VAL(Number$))
                IF OldLineNumber > False AND OldLineNumber <= MaxLines THEN
                    FOR NewLineNumber = 1 TO MaxLines
                        IF RenumberList(NewLineNumber) = OldLineNumber THEN
                            Program$(LineNumber) = NextProgramLine$ + LTRIM$(STR$(NewLineNumber))
                            LineRenumbered = True
                            EXIT FOR
                        END IF
                    NEXT
                END IF
            END IF
            IF UCASE$(LEFT$(OldProgramLine$, 13)) = "ON ERROR GOTO" THEN
                LineRenumbered = False
                Imbedded = INSTR(UCASE$(NewProgramLine$), "GOTO") + 4
                GOSUB NextSpace
                Number$ = MID$(OldProgramLine$, 14)
                Number$ = STRIM$(Number$)
                OldLineNumber = INT(VAL(Number$))
                IF OldLineNumber > False AND OldLineNumber <= MaxLines THEN
                    FOR NewLineNumber = 1 TO MaxLines
                        IF RenumberList(NewLineNumber) = OldLineNumber THEN
                            Program$(LineNumber) = NextProgramLine$ + LTRIM$(STR$(NewLineNumber))
                            LineRenumbered = True
                            EXIT FOR
                        END IF
                    NEXT
                END IF
            END IF
            IF UCASE$(LEFT$(OldProgramLine$, 6)) = "RESUME" THEN
                IF UCASE$(LEFT$(OldProgramLine$, 15)) <> "RESUME PREVIOUS" THEN
                    IF UCASE$(LEFT$(OldProgramLine$, 11)) <> "RESUME SAME" THEN
                        IF UCASE$(LEFT$(OldProgramLine$, 11)) <> "RESUME NEXT" THEN
                            LineRenumbered = False
                            Imbedded = INSTR(UCASE$(NewProgramLine$), "RESUME") + 6
                            GOSUB NextSpace
                            Number$ = MID$(OldProgramLine$, 7)
                            Number$ = STRIM$(Number$)
                            OldLineNumber = INT(VAL(Number$))
                            IF OldLineNumber > False AND OldLineNumber <= MaxLines THEN
                                FOR NewLineNumber = 1 TO MaxLines
                                    IF RenumberList(NewLineNumber) = OldLineNumber THEN
                                        Program$(LineNumber) = NextProgramLine$ + LTRIM$(STR$(NewLineNumber))
                                        LineRenumbered = True
                                        EXIT FOR
                                    END IF
                                NEXT
                            END IF
                        END IF
                    END IF
                END IF
            END IF
            IF UCASE$(LEFT$(OldProgramLine$, 5)) = "GOSUB" THEN
                LineRenumbered = False
                Imbedded = INSTR(UCASE$(NewProgramLine$), "GOSUB") + 5
                GOSUB NextSpace
                Number$ = MID$(OldProgramLine$, 6)
                Number$ = STRIM$(Number$)
                OldLineNumber = INT(VAL(Number$))
                IF OldLineNumber > False AND OldLineNumber <= MaxLines THEN
                    FOR NewLineNumber = 1 TO MaxLines
                        IF RenumberList(NewLineNumber) = OldLineNumber THEN
                            Program$(LineNumber) = NextProgramLine$ + LTRIM$(STR$(NewLineNumber))
                            LineRenumbered = True
                            EXIT FOR
                        END IF
                    NEXT
                END IF
            END IF
            IF UCASE$(LEFT$(OldProgramLine$, 2)) = "ON" THEN
                IF UCASE$(LEFT$(OldProgramLine$, 8)) <> "ON ERROR" THEN
                    LineRenumbered = False
                    IF INSTR(UCASE$(OldProgramLine$), "GOTO") THEN
                        Imbedded = INSTR(UCASE$(NewProgramLine$), "GOTO") + 4
                        OldNumber1$ = LTRIM$(MID$(NewProgramLine$, Imbedded))
                        GOSUB NextSpace
                        NewProgramLine1$ = NextProgramLine$
                        Imbedded2 = INSTR(UCASE$(OldProgramLine$), "GOTO")
                        OldNumber2$ = MID$(OldProgramLine$, Imbedded2 + 4)
                        DO
                            Imbedded1 = INSTR(OldNumber1$, ",")
                            IF Imbedded1 THEN
                                NewNumber1$ = LEFT$(OldNumber1$, Imbedded1 - 1)
                                OldNumber1$ = MID$(OldNumber1$, Imbedded1 + 1)
                            ELSE
                                NewNumber1$ = OldNumber1$
                                OldNumber1$ = Nul
                            END IF
                            IF INSTR(WhiteSpace, MID$(NewNumber1$, 1, 1)) THEN
                                Imbedded = 1
                                NewProgramLine$ = NewNumber1$
                                GOSUB NextSpace
                                NewNumber1$ = NextProgramLine$
                            ELSE
                                NewNumber1$ = Nul
                            END IF
                            Imbedded2 = INSTR(OldNumber2$, ",")
                            IF Imbedded2 THEN
                                NewNumber2$ = LEFT$(OldNumber2$, Imbedded2 - 1)
                                OldNumber2$ = MID$(OldNumber2$, Imbedded2 + 1)
                            ELSE
                                NewNumber2$ = OldNumber2$
                                OldNumber2$ = Nul
                            END IF
                            LineRenumbered = False
                            OldLineNumber = INT(VAL(NewNumber2$))
                            IF OldLineNumber > False AND OldLineNumber <= MaxLines THEN
                                FOR NewLineNumber = 1 TO MaxLines
                                    IF RenumberList(NewLineNumber) = OldLineNumber THEN
                                        NewProgramLine1$ = NewProgramLine1$ + NewNumber1$ + LTRIM$(STR$(NewLineNumber)) + ","
                                        LineRenumbered = True
                                        EXIT FOR
                                    END IF
                                NEXT
                            END IF
                            IF OldNumber2$ = Nul THEN
                                EXIT DO
                            END IF
                            IF LineRenumbered = False THEN
                                EXIT DO
                            END IF
                        LOOP
                        IF RIGHT$(NewProgramLine1$, 1) = "," THEN
                            NewProgramLine1$ = LEFT$(NewProgramLine1$, LEN(NewProgramLine1$) - 1)
                        END IF
                        Program$(LineNumber) = NewProgramLine1$
                    ELSE
                        IF INSTR(UCASE$(OldProgramLine$), "GOSUB") THEN
                            Imbedded = INSTR(UCASE$(NewProgramLine$), "GOSUB") + 5
                            OldNumber1$ = LTRIM$(MID$(NewProgramLine$, Imbedded))
                            GOSUB NextSpace
                            NewProgramLine1$ = NextProgramLine$
                            Imbedded2 = INSTR(UCASE$(OldProgramLine$), "GOSUB")
                            OldNumber2$ = MID$(OldProgramLine$, Imbedded2 + 5)
                            DO
                                Imbedded1 = INSTR(OldNumber1$, ",")
                                IF Imbedded1 THEN
                                    NewNumber1$ = LEFT$(OldNumber1$, Imbedded1 - 1)
                                    OldNumber1$ = MID$(OldNumber1$, Imbedded1 + 1)
                                ELSE
                                    NewNumber1$ = OldNumber1$
                                    OldNumber1$ = Nul
                                END IF
                                IF INSTR(WhiteSpace, MID$(NewNumber1$, 1, 1)) THEN
                                    Imbedded = 1
                                    NewProgramLine$ = NewNumber1$
                                    GOSUB NextSpace
                                    NewNumber1$ = NextProgramLine$
                                ELSE
                                    NewNumber1$ = Nul
                                END IF
                                Imbedded2 = INSTR(OldNumber2$, ",")
                                IF Imbedded2 THEN
                                    NewNumber2$ = LEFT$(OldNumber2$, Imbedded2 - 1)
                                    OldNumber2$ = MID$(OldNumber2$, Imbedded2 + 1)
                                ELSE
                                    NewNumber2$ = OldNumber2$
                                    OldNumber2$ = Nul
                                END IF
                                LineRenumbered = False
                                OldLineNumber = INT(VAL(NewNumber2$))
                                IF OldLineNumber > False AND OldLineNumber <= MaxLines THEN
                                    FOR NewLineNumber = 1 TO MaxLines
                                        IF RenumberList(NewLineNumber) = OldLineNumber THEN
                                            NewProgramLine1$ = NewProgramLine1$ + NewNumber1$ + LTRIM$(STR$(NewLineNumber)) + ","
                                            LineRenumbered = True
                                            EXIT FOR
                                        END IF
                                    NEXT
                                END IF
                                IF OldNumber2$ = Nul THEN
                                    EXIT DO
                                END IF
                                IF LineRenumbered = False THEN
                                    EXIT DO
                                END IF
                            LOOP
                            IF RIGHT$(NewProgramLine1$, 1) = "," THEN
                                NewProgramLine1$ = LEFT$(NewProgramLine1$, LEN(NewProgramLine1$) - 1)
                            END IF
                            Program$(LineNumber) = NewProgramLine1$
                        END IF
                    END IF
                END IF
            END IF
            IF LineRenumbered = False THEN
                COLOR White, Black
                PRINT "Error renumbering program: line"; LineNumber
                Filename = TempFilename$ + ".sc1"
                CALL ReadProgram
                COLOR White, Black
                PRINT "Program reloaded."
                KILL Filename
                REM ERASE RenumberList
                EXIT SUB
            END IF
        END IF
    NEXT
    PRINT "Resequencing line numbers.."
    Filename = TempFilename$ + ".sc1"
    CALL StoreProgram
    X = FreeFileNumber
    OPEN Filename FOR INPUT AS #FileNumber
    CALL NewProgram
    WHILE NOT EOF(FileNumber)
        LINE INPUT #FileNumber, NewProgramLine$
        FOR Blanks = 1 TO LEN(WhiteSpace)
            Imbedded = INSTR(NewProgramLine$, MID$(WhiteSpace, Blanks, 1))
            IF Imbedded THEN
                EXIT FOR
            END IF
        NEXT
        OldLineNumber = INT(VAL(LEFT$(NewProgramLine$, Imbedded - 1)))
        FOR NewProgramLine = 1 TO MaxLines
            IF RenumberList(NewProgramLine) = OldLineNumber THEN
                Program$(NewProgramLine) = MID$(NewProgramLine$, Imbedded)
                EXIT FOR
            END IF
        NEXT
    WEND
    CLOSE #FileNumber
    FileNumber = False
    COLOR White, Black
    PRINT "Program renumbered."
    KILL Filename
    REM ERASE RenumberList
    EXIT SUB

    ' locates string with following white spaces
    NextSpace:
    NextProgramLine$ = NewProgramLine$
    DO
        IF Imbedded >= LEN(NextProgramLine$) THEN
            EXIT DO
        END IF
        IF INSTR(WhiteSpace, MID$(NextProgramLine$, Imbedded + 1, 1)) THEN
            Imbedded = Imbedded + 1
        ELSE
            EXIT DO
        END IF
    LOOP
    NextProgramLine$ = LEFT$(NextProgramLine$, Imbedded)
    RETURN
END SUB

' starts current .sic program
SUB RunProgram (StartLine)
    ' check to continue halted program.
    IF RunType THEN
        COLOR Plain, Black
        GOTO RunProg
    END IF

    ErrorCount = 0
    ErrorType2 = -1

    ' close any files
    CLOSE

    ' restore run variables
    DebugActive = -1
    DataLine = 1
    DataNumber = False
    ErrorLine = False
    ErrorType = False
    ErrorValue = False
    NestedGosub = False
    MaxGosubs = 10
    ScreenMode = 0
    ScreenHeight = 25
    ScreenWidth = 80
    Visible = 1
    COLOR Plain, Black

    ' clear runtime arrays
    REDIM GosubReturn(1 TO 10) AS INTEGER
    FOR Count1 = 1 TO 26
        Variables(Count1) = Dfalse
        Strngs$(Count1) = Nul
        FOR Count2 = 1 TO MaxArrays
            Arrays(Count1, Count2) = Dfalse
        NEXT
    NEXT
    FOR Count1 = 1 TO MaxFunctions
        Definitions$(Count1) = Nul
    NEXT

    ' start program processing loop.
    RunProg:

    ' start program execution
    CALL PrepareProgram

    ' check program validity
    CALL AnalyzeProgram(0, VarX, Var$)
    IF VarX THEN
        COLOR White
        PRINT "Program analyze error line:" + STR$(ProgramLine) + ": " + Var$ + "."
        RunLine = MaxLines + 1
        CLOSE
        GOSUB ReadProg
        EXIT SUB
    END IF

    ' check starting line number
    CALL CountLines(LastLine)

    ' check to continue halted program.
    IF RunType THEN
        ' restore last program line processed.
        ProgramLine = RunLine
    ELSE
        ' store first program line.
        ProgramLine = False
        IF StartLine THEN
            IF StartLine > False AND StartLine <= LastLine THEN
                IF LEN(STRIM$(Program$(StartLine))) THEN
                    ProgramLine = StartLine - 1
                ELSE
                    GOTO RunError
                END IF
            ELSE
                GOTO RunError
            END IF
        END IF
    END IF

    ' reset segment flag
    IF RunType THEN
        InDEFSEG = InDEFSEG2
    ELSE
        InDEFSEG = False
        InDEFSEG2 = False
    END IF

    ' reset colors
    IF RunType THEN
        COLOR LastColor1, LastColor2
    ELSE
        LastColor1 = Plain
        LastColor2 = Black
    END IF

    ' reset screen width
    IF RunType THEN
        WIDTH LastWidth1, LastWidth2
    ELSE
        LastWidth1 = 80
        LastWidth2 = 25
    END IF

    ' reset screen mode
    IF RunType THEN
        SCREEN LastScreen1, LastScreen2, LastScreen3, LastScreen4
    ELSE
        LastScreen1 = 0
        LastScreen2 = 1
        LastScreen3 = 0
        LastScreen4 = 0
    END IF

    ' reset cursor size
    IF RunType THEN
        LOCATE , , LastCursor1, LastCursor2, LastCursor3
    ELSE
        LastCursor1 = 1
        LastCursor2 = 8
        LastCursor3 = 8
    END IF

    ' start program flow
    BreakFlag1 = False
    BreakFlag2 = False
    BreakFlag3 = False
    BreakFlag4 = False
    BreakFlag5 = False
    BreakFlag6 = False
    BreakFlag7 = False

    ' check for break variables
    FOR VarBreak = 1 TO 26
        IF VariableBreak(VarBreak) THEN
            ' store first break variable
            BreakFlag3 = VarBreak
            EXIT FOR
        END IF
    NEXT

    ' check for break variables
    FOR VarBreak = 1 TO 26
        IF LEN(VariableBreak2(VarBreak)) <> False THEN
            ' store first break variable
            BreakFlag5 = VarBreak
            EXIT FOR
        END IF
    NEXT

    ' check for break variables
    FOR VarBreak = 1 TO 26
        FOR VarBreak2 = 1 TO MaxArrays
            IF VariableBreak3(VarBreak, VarBreak2) THEN
                ' store first break variable
                BreakFlag7 = VarBreak
                EXIT FOR
            END IF
        NEXT
        IF BreakFlag7 THEN
            EXIT FOR
        END IF
    NEXT

    ' start program loop
    _TITLE "SICK64 - " + ProgramName
    ProgramRunning = -1
    DO
        ' increment program flow
        ProgramLine = ProgramLine + 1
        IF ProgramLine > LastLine THEN
            ProgramLine = MaxLines + 1
        END IF
        IF ProgramLine > MaxLines THEN
            EXIT DO
        END IF

        ' test line list/line break
        IF DebugActive THEN
            IF LEN(Program$(ProgramLine)) <> False THEN
                ' display debug list line
                IF ListLines THEN
                    IF POS(0) > 1 THEN
                        PRINT
                    END IF
                    PRINT "Debug line:" + STR$(ProgramLine) + "."
                END IF
                ' test break lines
                IF LineBreak(ProgramLine) THEN
                    BreakFlag1 = True
                    EXIT DO
                END IF
            END IF
        END IF

        ' process the program line
        Out2 = STRIM$(Program$(ProgramLine))
        IF LEN(Out2) THEN

            ' clear recurse flag
            Recurse = 0

            ' enter the parser
            CALL EnterEquate

            ' test break variables
            IF DebugActive THEN
                IF BreakFlag3 THEN
                    GOSUB TestBreak1
                    IF BreakFlag2 THEN
                        EXIT DO
                    END IF
                END IF
                IF BreakFlag5 THEN
                    GOSUB TestBreak2
                    IF BreakFlag4 THEN
                        EXIT DO
                    END IF
                END IF
                IF BreakFlag7 THEN
                    GOSUB TestBreak3
                    IF BreakFlag6 THEN
                        EXIT DO
                    END IF
                END IF
            END IF
        END IF
    LOOP

    ' store last program line processed.
    RunLine = ProgramLine
    ProgramRunning = 0

    ' store segment flag.
    InDEFSEG2 = InDEFSEG

    ' end program parsing
    _TITLE "SICK64"
    CALL EndProgram

    ' stop processing program
    ProgramLine = MaxLines

    ' display any break messages
    IF BreakFlag1 THEN
        COLOR Red, Black
        PRINT "*line break*"
        COLOR Yellow, Black
        PRINT "Line:" + STR$(RunLine) + "."
    END IF
    IF BreakFlag2 THEN
        COLOR Red, Black
        PRINT "*variable break*"
        COLOR Yellow, Black
        PRINT "Line:" + STR$(RunLine) + "."
        PRINT "Variable: " + CHR$(VarBreak + 64)
        PRINT "Test: " + Symbol$ + " " + LTRIM$(STR$(VariableValue(VarBreak)))
        PRINT "Value: " + LTRIM$(STR$(Variables(VarBreak)))
    END IF
    IF BreakFlag4 THEN
        COLOR Red, Black
        PRINT "*variable break*"
        COLOR Yellow, Black
        PRINT "Line:" + STR$(RunLine) + "."
        PRINT "Variable: " + CHR$(VarBreak + 64) + "$"
        IF LEN(VariableValue2$(VarBreak)) > 40 THEN
            PRINT "Test: " + Symbol$ + " " + Quote + LEFT$(VariableValue2$(VarBreak), 40) + "..."
        ELSE
            PRINT "Test: " + Symbol$ + " " + Quote + VariableValue2$(VarBreak) + Quote
        END IF
        IF LEN(Strngs$(VarBreak)) > 40 THEN
            PRINT "Value: " + Quote + LEFT$(Strngs$(VarBreak), 40) + "..."
        ELSE
            PRINT "Value: " + Quote + Strngs$(VarBreak) + Quote
        END IF
    END IF
    IF BreakFlag6 THEN
        COLOR Red, Black
        PRINT "*variable break*"
        COLOR Yellow, Black
        PRINT "Line:" + STR$(RunLine) + "."
        PRINT "Variable: " + CHR$(VarBreak + 64) + "(" + MID$(STR$(VarBreak2), 2) + ")"
        PRINT "Test: " + Symbol$ + " " + LTRIM$(STR$(VariableValue3(VarBreak, VarBreak2)))
        PRINT "Value: " + " " + LTRIM$(STR$(Arrays(VarBreak, VarBreak2)))
    END IF
    IF BreakFlag1 THEN
        GOSUB ReadProg
        EXIT SUB
    END IF
    IF BreakFlag2 THEN
        GOSUB ReadProg
        EXIT SUB
    END IF
    IF BreakFlag4 THEN
        GOSUB ReadProg
        EXIT SUB
    END IF
    IF BreakFlag6 THEN
        GOSUB ReadProg
        EXIT SUB
    END IF
    CLOSE
    GOSUB ReadProg
    EXIT SUB

    ' exit with error
    RunError:
    CLOSE
    GOSUB ReadProg
    ERROR 145
    EXIT SUB

    ' read original program
    ReadProg:
    CALL RestoreProgram
    RETURN

    TestBreak1:
    ' start with first break variable
    FOR VarBreak = BreakFlag3 TO 26
        IF VariableBreak(VarBreak) THEN
            SELECT CASE VariableBreak(VarBreak)
                CASE -1
                    IF Variables(VarBreak) = VariableValue(VarBreak) THEN
                        BreakFlag2 = True
                        Symbol$ = "="
                        RETURN
                    END IF
                CASE 1
                    IF Variables(VarBreak) <> VariableValue(VarBreak) THEN
                        BreakFlag2 = True
                        Symbol$ = "<>"
                        RETURN
                    END IF
                CASE 2
                    IF Variables(VarBreak) > VariableValue(VarBreak) THEN
                        BreakFlag2 = True
                        Symbol$ = ">"
                        RETURN
                    END IF
                CASE 3
                    IF Variables(VarBreak) >= VariableValue(VarBreak) THEN
                        BreakFlag2 = True
                        Symbol$ = ">="
                        RETURN
                    END IF
                CASE 4
                    IF Variables(VarBreak) < VariableValue(VarBreak) THEN
                        BreakFlag2 = True
                        Symbol$ = "<"
                        RETURN
                    END IF
                CASE 5
                    IF Variables(VarBreak) <= VariableValue(VarBreak) THEN
                        BreakFlag2 = True
                        Symbol$ = "<="
                        RETURN
                    END IF
            END SELECT
        END IF
    NEXT
    RETURN

    TestBreak2:
    ' start with first break variable
    FOR VarBreak = BreakFlag5 TO 26
        IF VariableBreak2(VarBreak) THEN
            SELECT CASE VariableBreak2(VarBreak)
                CASE -1
                    IF Strngs$(VarBreak) = VariableValue2$(VarBreak) THEN
                        BreakFlag4 = True
                        Symbol$ = "="
                        RETURN
                    END IF
                CASE 1
                    IF Strngs$(VarBreak) <> VariableValue2$(VarBreak) THEN
                        BreakFlag4 = True
                        Symbol$ = "<>"
                        RETURN
                    END IF
                CASE 2
                    IF Strngs$(VarBreak) > VariableValue2$(VarBreak) THEN
                        BreakFlag4 = True
                        Symbol$ = ">"
                        RETURN
                    END IF
                CASE 3
                    IF Strngs$(VarBreak) >= VariableValue2$(VarBreak) THEN
                        BreakFlag4 = True
                        Symbol$ = ">="
                        RETURN
                    END IF
                CASE 4
                    IF Strngs$(VarBreak) < VariableValue2$(VarBreak) THEN
                        BreakFlag4 = True
                        Symbol$ = "<"
                        RETURN
                    END IF
                CASE 5
                    IF Strngs$(VarBreak) <= VariableValue2$(VarBreak) THEN
                        BreakFlag4 = True
                        Symbol$ = "<="
                        RETURN
                    END IF
            END SELECT
        END IF
    NEXT
    RETURN

    TestBreak3:
    ' start with first break variable
    FOR VarBreak = BreakFlag7 TO 26
        FOR VarBreak2 = 1 TO MaxArrays
            IF VariableBreak3(VarBreak, VarBreak2) THEN
                SELECT CASE VariableBreak3(VarBreak, VarBreak2)
                    CASE -1
                        IF Arrays(VarBreak, VarBreak2) = VariableValue3(VarBreak, VarBreak2) THEN
                            BreakFlag6 = True
                            Symbol$ = "="
                            RETURN
                        END IF
                    CASE 1
                        IF Arrays(VarBreak, VarBreak2) <> VariableValue3(VarBreak, VarBreak2) THEN
                            BreakFlag6 = True
                            Symbol$ = "<>"
                            RETURN
                        END IF
                    CASE 2
                        IF Arrays(VarBreak, VarBreak2) > VariableValue3(VarBreak, VarBreak2) THEN
                            BreakFlag6 = True
                            Symbol$ = ">"
                            RETURN
                        END IF
                    CASE 3
                        IF Arrays(VarBreak, VarBreak2) >= VariableValue3(VarBreak, VarBreak2) THEN
                            BreakFlag6 = True
                            Symbol$ = ">="
                            RETURN
                        END IF
                    CASE 4
                        IF Arrays(VarBreak, VarBreak2) < VariableValue3(VarBreak, VarBreak2) THEN
                            BreakFlag6 = True
                            Symbol$ = "<"
                            RETURN
                        END IF
                    CASE 5
                        IF Arrays(VarBreak, VarBreak2) <= VariableValue3(VarBreak, VarBreak2) THEN
                            BreakFlag6 = True
                            Symbol$ = "<="
                            RETURN
                        END IF
                END SELECT
            END IF
        NEXT
    NEXT
    RETURN
END SUB

' reads original program after program halt or error
SUB RestoreProgram
    CALL NewProgram
    Filename = PrepareFilename
    CALL ReadProgram
    IF _FILEEXISTS(PrepareFilename) THEN
        KILL PrepareFilename
    END IF
END SUB

' prompts to store current .sic program
SUB SaveCurrent
    IF ProgramName <> None THEN
        CALL MorePrompt("Save current program(y/n)?", "yn", OutputChar$)
        IF OutputChar$ = "y" THEN
            CALL SaveProgram(Nul)
        END IF
    END IF
END SUB

' stores current .sic program
SUB SaveProgram (Var$)
    DO
        IF Var$ <> Nul THEN
            ProgramFile$ = Var$
        END IF
        IF Var$ = Nul THEN
            DO
                COLOR Yellow, Black
                PRINT "Program name to save";
                IF ProgramName <> Untitled THEN
                    COLOR White, Black
                    PRINT "("; ProgramName; ")";
                END IF
                PRINT "? ";
                LINE INPUT ProgramFile$
                IF ProgramFile$ <> Nul THEN
                    EXIT DO
                END IF
                IF ProgramFile$ = Nul THEN
                    IF ProgramName <> Untitled THEN
                        ProgramFile$ = ProgramName
                        EXIT DO
                    END IF
                END IF
            LOOP
        END IF
        CALL Concatenate(ProgramFile$)
        Filename = ProgramFile$
        IF Var$ = Nul THEN
            COLOR Cyan, Black
            PRINT "Save program as " + Quote + Filename + Quote;
            CALL MorePrompt(MorePrompt3, "ynq", OutputChar$)
        ELSE
            OutputChar$ = "y"
        END IF
        SELECT CASE OutputChar$
            CASE "y"
                IF Var$ = Nul THEN
                    OutputChar$ = "y"
                    IF _FILEEXISTS(Filename) THEN
                        COLOR Red, Black
                        PRINT "Program already exists. ";
                        CALL MorePrompt("Overwrite(y/n)?", "yn", OutputChar$)
                    END IF
                ELSE
                    OutputChar$ = "y"
                END IF
                IF OutputChar$ = "y" THEN
                    ErrorValue = False
                    CALL StoreProgram
                    IF ErrorValue = False THEN
                        ProgramName = ProgramFile$
                        COLOR White, Black
                        PRINT "Program " + Quote + Filename + Quote + " saved to disk."
                    END IF
                    EXIT DO
                END IF
            CASE "q"
                COLOR White, Black
                PRINT "Program not saved to disk."
                EXIT DO
        END SELECT
    LOOP
END SUB

' writes out the current .sic program to file
SUB StoreProgram
    X = FreeFileNumber
    OPEN Filename FOR OUTPUT AS #FileNumber
    CALL CountLines(LastLine)
    FOR LineNumber = 1 TO LastLine
        ProgramLine$ = Program$(LineNumber)
        IF STRIM$(ProgramLine$) <> Nul THEN
            IF INSTR(WhiteSpace, LEFT$(ProgramLine$, 1)) THEN
                PRINT #FileNumber, MID$(STR$(LineNumber), 2) + ProgramLine$
            ELSE
                PRINT #FileNumber, MID$(STR$(LineNumber), 2) + " " + ProgramLine$
            END IF
        END IF
    NEXT
    CLOSE #FileNumber
    FileNumber = False
END SUB

' immediate debugging prompt.
SUB DebugCommand
    COLOR White, Black
    PRINT "Type 'Quit' to exit Debug mode."
    PRINT "Or type ? for brief command list."
    DO
        Visible = 1
        COLOR Yellow, Black
        LOCATE , 1, 1
        PRINT Prompt3;
        LOCATE , , 1
        Temp0 = 3
        Out2 = KeyboardLine2$
        PRINT

        ' parse debug commands
        Var$ = Out2
        Out2 = UCASE$(Out2)
        IF Out2 = "QUIT" THEN
            EXIT DO
        END IF
        IF Out2 = "LISTLINES" THEN ' LL
            Out2 = "LL"
        END IF
        IF LEFT$(Out2, 8) = "SETBREAK" THEN ' SB
            Out2 = "SB" + MID$(Out2, 9)
        END IF
        IF LEFT$(Out2, 10) = "CLEARBREAK" THEN ' CB
            Out2 = "CB" + MID$(Out2, 11)
        END IF
        IF Out2 = "LISTBREAKS" THEN ' LB
            Out2 = "LB"
        END IF
        IF Out2 = "CLEARALLBREAKS" THEN ' CA
            Out2 = "CA"
        END IF
        IF LEFT$(Out2, 11) = "SETVARIABLE" THEN ' SV
            Out2 = "SV" + MID$(Out2, 12)
        END IF
        IF LEFT$(Out2, 13) = "CLEARVARIABLE" THEN ' CV
            Out2 = "CV" + MID$(Out2, 14)
        END IF
        IF LEFT$(Out2, 14) = "TOGGLEVARIABLE" THEN ' TV
            Out2 = "TV" + MID$(Out2, 15)
        END IF
        IF Out2 = "LISTVARIABLES" THEN ' LV
            Out2 = "LV"
        END IF
        IF Out2 = "CLEARALLVARIABLES" THEN ' AV
            Out2 = "AV"
        END IF

        ' parse shortcuts
        SELECT CASE LEFT$(Out2, 2)
            CASE "LL"
                IF LEN(Out2) = 2 THEN
                    ListLines = NOT ListLines
                    IF ListLines THEN
                        PRINT "Debug: List lines on."
                    ELSE
                        PRINT "Debug: List lines off."
                    END IF
                ELSE
                    COLOR White, Black
                    PRINT "Unknown command."
                END IF
            CASE "SB"
                GOSUB SetBreak
            CASE "CB"
                GOSUB ClearBreak
            CASE "LB"
                IF LEN(Out2) = 2 THEN
                    GOSUB DisplayBreaks
                ELSE
                    COLOR White, Black
                    PRINT "Unknown command."
                END IF
            CASE "CA"
                IF LEN(Out2) = 2 THEN
                    GOSUB ClearAllBreaks
                ELSE
                    COLOR White, Black
                    PRINT "Unknown command."
                END IF
            CASE "SV"
                GOSUB SetVariable
            CASE "CV"
                GOSUB ClearVariable
            CASE "TV"
                GOSUB ToggleVariable
            CASE "LV"
                IF LEN(Out2) = 2 THEN
                    GOSUB DisplayVariables
                ELSE
                    COLOR White, Black
                    PRINT "Unknown command."
                END IF
            CASE "AV"
                IF LEN(Out2) = 2 THEN
                    GOSUB ClearAllVariables
                ELSE
                    COLOR White, Black
                    PRINT "Unknown command."
                END IF
            CASE ELSE
                ' list commands
                IF Out2 = "?" THEN
                    COLOR Yellow, Black
                    PRINT "Brief list of Debug commands:"
                    PRINT "Command               Shortcut"
                    PRINT "-------------------   ---------"
                    COLOR White, Black
                    PRINT "LISTLINES             LL"
                    PRINT "SETBREAK <l>          SB <l>"
                    PRINT "CLEARBREAK <l>        CB <l>"
                    PRINT "LISTBREAKS            LB"
                    PRINT "CLEARALLBREAKS        CA"
                    PRINT "SETVARIABLE <x>,<n>   SV <x>,<n>"
                    PRINT "CLEARVARIABLE <x>     CV <x>"
                    PRINT "TOGGLEVARIABLE <x>    TV <x>"
                    PRINT "LISTVARIABLES         LV"
                    PRINT "CLEARALLVARIABLES     AV"
                ELSE
                    ' parse whatis
                    Out2 = Var$
                    COLOR Plain, Black
                    Out2 = TTRIM$(Out2, True)
                    ' clear recurse flag
                    Recurse = 0
                    ' start the parser
                    CALL EnterEquate
                    IF LineFeed THEN
                        PRINT
                    END IF
                END IF
        END SELECT
    LOOP
    COLOR White, Black
    PRINT "Debug mode ended."
    EXIT SUB

    DisplayVariables:
    Continuous = False
    LineCount = False
    Line.Flag = False
    FOR Var = 1 TO 26
        ' display break variables
        IF VariableBreak(Var) THEN
            ' check page length
            GOSUB CheckTitle
            COLOR Yellow, Black
            PRINT " "; CHR$(Var + 64); "        ";
            BreakSign = VariableBreak(Var)
            GOSUB GetSign
            PRINT Symbol$; "   ";
            PRINT STR$(VariableValue(Var))
            Line.Flag = True
        END IF

        ' check page length
        IF LineCount = PageLength - 2 THEN
            GOSUB CheckPage
            SELECT CASE OutputChar$
                CASE "n"
                    RETURN
                CASE "c"
                    Continuous = True
            END SELECT
        END IF
    NEXT
    FOR Var = 1 TO 26
        ' display break variables
        IF VariableBreak2(Var) THEN
            ' check page length
            GOSUB CheckTitle
            COLOR Yellow, Black
            PRINT " "; CHR$(Var + 64); "$       ";
            BreakSign = VariableBreak2(Var)
            GOSUB GetSign
            PRINT Symbol$; "   ";
            IF LEN(VariableValue2$(Var)) > 40 THEN
                PRINT Quote + LEFT$(VariableValue2$(Var), 40) + "..."
            ELSE
                PRINT Quote + VariableValue2$(Var) + Quote
            END IF
            Line.Flag = True
        END IF

        ' check page length
        IF LineCount = PageLength - 2 THEN
            GOSUB CheckPage
            SELECT CASE OutputChar$
                CASE "n"
                    RETURN
                CASE "c"
                    Continuous = True
            END SELECT
        END IF
    NEXT
    FOR Var = 1 TO 26
        FOR Var2 = 1 TO MaxArrays
            ' display break variables
            IF VariableBreak3(Var, Var2) THEN
                ' check page length
                GOSUB CheckTitle
                COLOR Yellow, Black
                PRINT " "; CHR$(Var + 64); "("; MID$(STR$(Var2), 2); ")  ";
                IF Var2 > 99 THEN
                    PRINT " ";
                ELSE
                    IF Var2 > 9 THEN
                        PRINT "  ";
                    ELSE
                        PRINT "   ";
                    END IF
                END IF
                BreakSign = VariableBreak3(Var, Var2)
                GOSUB GetSign
                PRINT Symbol$; "   ";
                PRINT STR$(VariableValue3(Var, Var2))
                Line.Flag = True
            END IF

            ' check page length
            IF LineCount = PageLength - 2 THEN
                GOSUB CheckPage
                SELECT CASE OutputChar$
                    CASE "n"
                        RETURN
                    CASE "c"
                        Continuous = True
                END SELECT
            END IF
        NEXT
    NEXT
    IF Line.Flag = False THEN
        COLOR White, Black
        PRINT "No variable breaks set."
    END IF
    RETURN

    DisplayBreaks:
    Continuous = False
    LineCount = False
    Line.Flag = False
    FOR Var = 1 TO MaxLines
        ' display break variables
        IF LineBreak(Var) THEN
            ' check page length
            LineCount = LineCount + 1
            IF Continuous = False THEN
                IF LineCount = 1 THEN
                    COLOR White, Black
                    PRINT "Line Number"
                    PRINT "-----------"
                END IF
            END IF
            COLOR Yellow, Black
            PRINT STR$(Var)
            Line.Flag = True
        END IF

        ' check page length
        IF LineCount = PageLength - 2 THEN
            GOSUB CheckPage
            SELECT CASE OutputChar$
                CASE "n"
                    RETURN
                CASE "c"
                    Continuous = True
            END SELECT
        END IF
    NEXT
    IF Line.Flag = False THEN
        COLOR White, Black
        PRINT "No line breaks set."
    END IF
    RETURN

    CheckPage:
    LineCount = False
    IF Continuous = False THEN
        CALL MorePrompt(MorePrompt1, "ync" + CHR$(13), OutputChar$)
    END IF
    RETURN

    CheckTitle:
    LineCount = LineCount + 1
    IF Continuous = False THEN
        IF LineCount = 1 THEN
            COLOR White, Black
            PRINT "Variable  Sign Value"
            PRINT "--------------------"
        END IF
    END IF
    RETURN

    GetSign:
    SELECT CASE BreakSign
        CASE -1
            Symbol$ = "= "
        CASE 1
            Symbol$ = "<>"
        CASE 2
            Symbol$ = "> "
        CASE 3
            Symbol$ = ">="
        CASE 4
            Symbol$ = "< "
        CASE 5
            Symbol$ = "<="
    END SELECT
    RETURN

    SetBreak:
    BreakLine = INT(VAL(MID$(Out2, 3)))
    IF BreakLine >= False AND BreakLine <= MaxLines THEN
        LineBreak(BreakLine) = True
        COLOR White, Black
        PRINT "Break line" + STR$(BreakLine) + " set."
        RETURN
    END IF
    COLOR White, Black
    PRINT "Unknown line."
    RETURN

    ClearBreak:
    BreakLine = INT(VAL(MID$(Out2, 3)))
    IF BreakLine >= False AND BreakLine <= MaxLines THEN
        LineBreak(BreakLine) = False
        COLOR White, Black
        PRINT "Break line" + STR$(BreakLine) + " cleared."
        RETURN
    END IF
    COLOR White, Black
    PRINT "Unknown line."
    RETURN

    SetVariable:
    Var$ = MID$(Out2, 3)
    Var$ = LTRIM$(Var$)
    Var2$ = LEFT$(Var$, 1)
    Var2$ = UCASE$(Var2$)
    IF Var2$ >= "A" AND Var2$ <= "Z" THEN
        BreakVar = ASC(Var2$) - 64
        Var$ = MID$(Var$, 2)
        Var$ = LTRIM$(Var$)
        IF LEFT$(Var$, 1) = "(" THEN
            Imbedded = INSTR(Var$, ")")
            IF Imbedded THEN
                Var2$ = LEFT$(Var$, Imbedded - 1)
                Var2$ = MID$(Var2$, 2)
                BreakVar2 = INT(VAL(Var2$))
                IF BreakVar2 >= 1 AND BreakVar2 <= MaxArrays THEN
                    Var$ = MID$(Var$, Imbedded + 1)
                    Var$ = LTRIM$(Var$)
                    IF LEFT$(Var$, 1) = "," THEN
                        BreakVar3# = VAL(MID$(Var$, 2))
                        VariableBreak3(BreakVar, BreakVar2) = True
                        VariableValue3(BreakVar, BreakVar2) = BreakVar3#
                        COLOR White, Black
                        PRINT "Break variable " + CHR$(BreakVar + 64) + "(" + MID$(STR$(BreakVar2), 2) + ")" + " set to " + LTRIM$(STR$(BreakVar3#)) + "."
                        RETURN
                    END IF
                END IF
            END IF
        ELSE
            IF LEFT$(Var$, 1) = "$" THEN
                Var$ = MID$(Var$, 2)
                Var$ = LTRIM$(Var$)
                IF LEFT$(Var$, 1) = "," THEN
                    BreakVar2$ = MID$(Var$, 2)
                    VariableBreak2(BreakVar) = True
                    VariableValue2$(BreakVar) = BreakVar2$
                    COLOR White, Black
                    PRINT "Break variable " + CHR$(BreakVar + 64) + "$ set to " + Quote + BreakVar2$ + Quote + "."
                    RETURN
                END IF
            ELSE
                IF LEFT$(Var$, 1) = "," THEN
                    BreakVar2# = VAL(MID$(Var$, 2))
                    VariableBreak(BreakVar) = True
                    VariableValue(BreakVar) = BreakVar2#
                    COLOR White, Black
                    PRINT "Break variable " + CHR$(BreakVar + 64) + " set to " + LTRIM$(STR$(BreakVar2#)) + "."
                    RETURN
                END IF
            END IF
        END IF
    END IF
    COLOR White, Black
    PRINT "Unknown variable."
    RETURN

    ClearVariable:
    Var$ = MID$(Out2, 3)
    Var$ = UCASE$(Var$)
    Var$ = RTRIM$(Var$)
    Var$ = LTRIM$(Var$)
    Var2$ = LEFT$(Var$, 1)
    IF Var2$ >= "A" AND Var2$ <= "Z" THEN
        BreakVar = ASC(Var2$) - 64
        IF LEN(Var$) = 1 THEN
            VariableBreak(BreakVar) = False
            VariableValue(BreakVar) = Dfalse
            COLOR White, Black
            PRINT "Break variable " + CHR$(BreakVar + 64) + " cleared."
            RETURN
        ELSE
            IF LEN(Var$) = 2 THEN
                Var2$ = MID$(Var$, 2)
                IF Var2$ = "$" THEN
                    VariableBreak2(BreakVar) = False
                    VariableValue2$(BreakVar) = Nul
                    COLOR White, Black
                    PRINT "Break variable " + CHR$(BreakVar + 64) + "$ cleared."
                    RETURN
                END IF
            ELSE
                Var$ = MID$(Var$, 2)
                IF LEFT$(Var$, 1) = "(" THEN
                    Imbedded = INSTR(Var$, ")")
                    IF Imbedded THEN
                        Var$ = LEFT$(Var$, Imbedded - 1)
                        Var$ = MID$(Var$, 2)
                        BreakVar2 = VAL(Var$)
                        IF BreakVar2 >= 1 AND BreakVar2 <= MaxArrays THEN
                            VariableBreak3(BreakVar, BreakVar2) = False
                            VariableValue3(BreakVar, BreakVar2) = Dfalse
                            COLOR White, Black
                            PRINT "Break variable " + CHR$(BreakVar + 64) + "(" + MID$(STR$(BreakVar2), 2) + ") cleared."
                            RETURN
                        END IF
                    END IF
                END IF
            END IF
        END IF
    END IF
    COLOR White, Black
    PRINT "Unknown variable."
    RETURN

    ToggleVariable:
    Var$ = MID$(Out2, 3)
    Var$ = UCASE$(Var$)
    Var$ = RTRIM$(Var$)
    Var$ = LTRIM$(Var$)
    Var2$ = LEFT$(Var$, 1)
    IF Var2$ >= "A" AND Var2$ <= "Z" THEN
        BreakVar = ASC(Var2$) - 64
        IF LEN(Var$) = 1 THEN
            IF VariableBreak(BreakVar) THEN
                NewBreak = VariableBreak(BreakVar)
                GOSUB NextBreak
                VariableBreak(BreakVar) = NewBreak
                COLOR White, Black
                PRINT "Break variable " + CHR$(BreakVar + 64) + " toggled to "; Symbol$; "."
                RETURN
            END IF
        ELSE
            IF LEN(Var$) = 2 THEN
                Var2$ = MID$(Var$, 2)
                IF Var2$ = "$" THEN
                    IF VariableBreak2(BreakVar) THEN
                        NewBreak = VariableBreak2(BreakVar)
                        GOSUB NextBreak
                        VariableBreak2(BreakVar) = NewBreak
                        COLOR White, Black
                        PRINT "Break variable " + CHR$(BreakVar + 64) + "$ toggled to "; Symbol$; "."
                        RETURN
                    END IF
                END IF
            ELSE
                Var$ = MID$(Var$, 2)
                IF LEFT$(Var$, 1) = "(" THEN
                    Imbedded = INSTR(Var$, ")")
                    IF Imbedded THEN
                        Var$ = LEFT$(Var$, Imbedded - 1)
                        Var$ = MID$(Var$, 2)
                        BreakVar2 = VAL(Var$)
                        IF BreakVar2 >= 1 AND BreakVar2 <= MaxArrays THEN
                            IF VariableBreak3(BreakVar, BreakVar2) THEN
                                NewBreak = VariableBreak3(BreakVar, BreakVar2)
                                GOSUB NextBreak
                                VariableBreak3(BreakVar, BreakVar2) = NewBreak
                                COLOR White, Black
                                PRINT "Break variable " + CHR$(BreakVar + 64) + "(" + MID$(STR$(BreakVar2), 2) + ") toggled to "; Symbol$; "."
                                RETURN
                            END IF
                        END IF
                    END IF
                END IF
            END IF
        END IF
    END IF
    COLOR White, Black
    PRINT "Unknown variable."
    RETURN

    NextBreak:
    SELECT CASE NewBreak
        CASE -1 ' =
            NewBreak = 1
            Symbol$ = "<>"
        CASE 1 ' <>
            NewBreak = 2
            Symbol$ = ">"
        CASE 2 ' >
            NewBreak = 3
            Symbol$ = ">="
        CASE 3 ' >=
            NewBreak = 4
            Symbol$ = "<"
        CASE 4 ' <
            NewBreak = 5
            Symbol$ = "<="
        CASE 5 ' <=
            NewBreak = True
            Symbol$ = "="
    END SELECT
    RETURN

    ClearAllBreaks:
    FOR BreakLine = 1 TO MaxLines
        LineBreak(BreakLine) = False
    NEXT
    COLOR White, Black
    PRINT "All line breaks cleared."
    RETURN

    ClearAllVariables:
    FOR BreakVar = 1 TO 26
        VariableBreak(BreakVar) = False
        VariableValue(BreakVar) = Dfalse
        VariableBreak2(BreakVar) = False
        VariableValue2$(BreakVar) = Nul
        FOR BreakVar2 = 1 TO MaxArrays
            VariableBreak3(BreakVar, BreakVar2) = False
            VariableValue3(BreakVar, BreakVar2) = Dfalse
        NEXT
    NEXT
    COLOR White, Black
    PRINT "All variable breaks cleared."
    RETURN
END SUB

' immediate parsing prompt.
SUB WhatisCommand (WhatValue$)
    ErrorType = False
    ErrorValue = False
    IF LEN(WhatValue$) THEN
        ProgramLine = False
        Out2 = TTRIM$(WhatValue$, True)
        ' clear recurse flag
        Recurse = 0
        ' start the parser
        CALL EnterEquate
        IF LineFeed THEN
            PRINT
        END IF
        CALL EndProgram
        COLOR White, Black
        PRINT "Whatis mode ended."
        EXIT SUB
    END IF
    COLOR White, Black
    PRINT "Type 'Quit' to exit Whatis mode."
    DO
        ProgramLine = False
        Visible = 1
        COLOR Yellow, Black
        LOCATE , 1, 1
        PRINT Prompt2;
        LOCATE , , 1
        Temp0 = 2
        Out2 = RTRIM$(KeyboardLine2$)
        PRINT
        IF UCASE$(Out2) = "QUIT" THEN
            EXIT DO
        END IF
        IF Out2 <> Nul THEN
            COLOR Plain, Black
            Out2 = TTRIM$(Out2, True)
            CALL TrimComment

            ' clear recurse flag
            Recurse = 0
            ' start the parser
            CALL EnterEquate
            IF LineFeed THEN
                PRINT
            END IF
        END IF
    LOOP
    CALL EndProgram
    COLOR White, Black
    PRINT "Whatis mode ended."
END SUB

' prepares program for analyze/run command
SUB PrepareProgram
    ' write out current program
    DO
        TempFilename$ = TempName$
        Filename = DRX + TempFilename$ + ".sc2"
        IF _FILEEXISTS(Filename) = 0 THEN
            EXIT DO
        END IF
    LOOP
    PrepareFilename = Filename
    CALL StoreProgram

    ' remove remark at end of line,
    '   search for end of matching double quotes
    '   which might contain an apostrophe.
    CALL CountLines(LastLine)
    FOR ProgramLine = 1 TO LastLine
        Out2 = STRIM$(Program$(ProgramLine))
        IF LEN(Out2) THEN
            StartChar = 1
            DO
                QuoteStart = False
                FOR Temp = StartChar TO LEN(Out2)
                    IF MID$(Out2, Temp, 1) = Quote THEN
                        QuoteStart = Temp
                        EXIT FOR
                    END IF
                NEXT
                IF QuoteStart = False THEN
                    EXIT DO
                END IF
                QuoteStop = False
                FOR Temp2 = QuoteStart + 1 TO LEN(Out2)
                    IF MID$(Out2, Temp2, 1) = Quote THEN
                        QuoteStop = Temp2
                        EXIT FOR
                    END IF
                NEXT
                IF QuoteStop = False THEN
                    EXIT DO
                END IF
                StartChar = QuoteStop + 1
            LOOP
            FOR Temp = StartChar TO LEN(Out2)
                IF MID$(Out2, Temp, 1) = "'" THEN
                    Out2 = LEFT$(Out2, Temp - 1)
                    EXIT FOR
                END IF
            NEXT
            Out2 = STRIM$(Out2)
            IF LEN(Out2) THEN
                Program$(ProgramLine) = Out2
            ELSE
                Program$(ProgramLine) = "REM"
                'Program$(ProgramLine) = Nul
            END IF
        END IF
    NEXT

    ' concatenate line continuation statements,
    ' remove continued lines.
    ProgramLine = False
    CALL CountLines(LastLine)
    DO
        ProgramLine = ProgramLine + 1
        IF ProgramLine > LastLine THEN
            EXIT DO
        END IF
        IF ProgramLine > MaxLines THEN
            EXIT DO
        END IF
        FirstLine = ProgramLine
        Out2 = STRIM$(Program$(ProgramLine))
        IF LEN(Out2) THEN
            DO
                IF RIGHT$(Out2, 1) = "_" THEN
                    Out2 = LEFT$(Out2, LEN(Out2) - 1)
                    FOR NextLine = ProgramLine + 1 TO LastLine
                        Out3 = STRIM$(Program$(NextLine))
                        IF LEN(Out3) THEN
                            Out2 = Out2 + Out3
                            ProgramLine = NextLine
                            Program$(NextLine) = "REM"
                            'Program$(NextLine) = Nul
                            EXIT FOR
                        END IF
                    NEXT
                ELSE
                    EXIT DO
                END IF
                Out2 = STRIM$(Out2)
            LOOP
            Program$(FirstLine) = Out2
        END IF
    LOOP

    ' compress program array,
    ' replaces all white spaces with single space,
    ' replaces all double spaces with single space.
    ProgramLine = False
    CALL CountLines(LastLine)
    FOR ProgramLine = 1 TO LastLine
        Out2 = STRIM$(Program$(ProgramLine))
        IF LEN(Out2) THEN
            Program$(ProgramLine) = TTRIM$(Out2, True)
        ELSE
            Program$(ProgramLine) = Nul
        END IF
    NEXT
END SUB

' replaces white spaces with spaces,
' var = true; skip spaces in quotes
FUNCTION TTRIM$ (Var$, Var)
    VarX$ = Var$
    Temp = False
    DO
        Temp = Temp + 1
        IF Temp > LEN(VarX$) THEN
            EXIT DO
        END IF
        IF Var THEN
            IF MID$(VarX$, Temp, 1) = Quote THEN
                DO
                    Temp = Temp + 1
                    IF Temp > LEN(VarX$) THEN
                        EXIT DO
                    END IF
                    IF MID$(VarX$, Temp, 1) = Quote THEN
                        EXIT DO
                    END IF
                LOOP
            END IF
        END IF
        FOR Blanks = 1 TO LEN(WhiteSpace)
            IF MID$(VarX$, Temp, 1) = MID$(WhiteSpace, Blanks, 1) THEN
                MID$(VarX$, Temp, 1) = " "
            END IF
        NEXT
    LOOP
    Temp = False
    DO
        Temp = Temp + 1
        IF Temp > LEN(VarX$) THEN
            EXIT DO
        END IF
        IF Var THEN
            IF MID$(VarX$, Temp, 1) = Quote THEN
                DO
                    Temp = Temp + 1
                    IF Temp > LEN(VarX$) THEN
                        EXIT DO
                    END IF
                    IF MID$(VarX$, Temp, 1) = Quote THEN
                        EXIT DO
                    END IF
                LOOP
            END IF
        END IF
        IF MID$(VarX$, Temp, 2) = "  " THEN
            VarX$ = LEFT$(VarX$, Temp) + MID$(VarX$, Temp + 2)
            Temp = Temp - 1
        END IF
    LOOP
    TTRIM$ = VarX$
END FUNCTION

' strips leading/trailing white spaces from string
FUNCTION STRIM$ (Var$)
    VarX$ = Var$
    DO
        Blanks = False
        FOR Count = 1 TO LEN(WhiteSpace)
            IF LEFT$(VarX$, 1) = MID$(WhiteSpace, Count, 1) THEN
                VarX$ = MID$(VarX$, 2)
                Blanks = True
            END IF
        NEXT
        IF Blanks = False THEN
            EXIT DO
        END IF
    LOOP
    DO
        Blanks = False
        FOR Count = 1 TO LEN(WhiteSpace)
            IF RIGHT$(VarX$, 1) = MID$(WhiteSpace, Count, 1) THEN
                VarX$ = LEFT$(VarX$, LEN(VarX$) - 1)
                Blanks = True
            END IF
        NEXT
        IF Blanks = False THEN
            EXIT DO
        END IF
    LOOP
    STRIM$ = VarX$
END FUNCTION

' replaces white spaces with nul,
' var = true; skip spaces in quotes
FUNCTION XTRIM$ (Var$, Var)
    VarX$ = Var$
    Temp = False
    DO
        Temp = Temp + 1
        IF Temp > LEN(VarX$) THEN
            EXIT DO
        END IF
        IF Var THEN
            IF MID$(VarX$, Temp, 1) = CHR$(34) THEN
                DO
                    Temp = Temp + 1
                    IF Temp > LEN(VarX$) THEN
                        EXIT DO
                    END IF
                    IF MID$(VarX$, Temp, 1) = CHR$(34) THEN
                        EXIT DO
                    END IF
                LOOP
            END IF
        END IF
        FOR Blanks = 1 TO LEN(WhiteSpace)
            IF MID$(VarX$, Temp, 1) = MID$(WhiteSpace, Blanks, 1) THEN
                VarX$ = LEFT$(VarX$, Temp - 1) + MID$(VarX$, Temp + 1)
                Temp = Temp - 1
                EXIT FOR
            END IF
        NEXT
    LOOP
    XTRIM$ = VarX$
END FUNCTION

' returns a randomized temporary filename.
'    could be generated from date/time.
FUNCTION TempName$
    Var$ = Nul
    FOR Temp = 1 TO 8
        Var$ = Var$ + HEX$(INT(RND * 16)) ' 0-9,A-F
    NEXT
    TempName$ = Var$
END FUNCTION

' uses direct keyboard input to get an input line
'   and edit multi-dimensional command history arrays with line-wrapping,
'     where Temp0 (history array type) equals:
'       1=command prompt
'       2=whatis prompt
'       3=debug prompt

FUNCTION KeyboardLine2$
    HistoryCount2(Temp0) = 0 ' reset
    Var$ = Nul
    DO
        _LIMIT 50
        Var2$ = INKEY$ ' get character
        IF LEN(Var2$) THEN
            SELECT CASE LEN(Var2$)
                CASE 1
                    SELECT CASE Var2$
                        CASE CHR$(9) ' tab
                            IF LEN(Var$) + 8 <= 256 THEN
                                FOR VarX = 1 TO 8
                                    PRINT " ";
                                    LOCATE , , Visible
                                    Var$ = Var$ + " "
                                NEXT
                            END IF
                        CASE CHR$(13) ' return
                            GOSUB EnterHistory
                            EXIT DO
                        CASE CHR$(8) ' backspace
                            IF LEN(Var$) > 0 THEN
                                Var$ = LEFT$(Var$, LEN(Var$) - 1)
                                GOSUB BackSpace
                            END IF
                        CASE CHR$(27) ' escape
                            GOSUB EraseLine
                        CASE ELSE ' store input
                            IF LEN(Var$) < 256 THEN
                                PRINT Var2$;
                                LOCATE , , Visible
                                Var$ = Var$ + Var2$
                            END IF
                    END SELECT
                CASE 2
                    SELECT CASE ASC(RIGHT$(Var2$, 1))
                        CASE 77 ' right
                            GOSUB GetCount
                            IF Var1 > 0 THEN
                                SELECT CASE HistoryCount2(Temp0)
                                    CASE 0
                                        GOSUB EraseLine
                                        HistoryCount2(Temp0) = Var1
                                        Var$ = RTRIM$(History2(Temp0, Var1))
                                        PRINT Var$;
                                    CASE 1 TO MaxHistory - 1
                                        IF HistoryCount2(Temp0) + 1 <= Var1 THEN
                                            GOSUB EraseLine
                                            HistoryCount2(Temp0) = HistoryCount2(Temp0) + 1
                                            Var$ = RTRIM$(History2(Temp0, HistoryCount2(Temp0)))
                                            PRINT Var$;
                                        ELSE
                                            IF HistoryCount2(Temp0) = Var1 THEN
                                                GOSUB EraseLine
                                                Var$ = RTRIM$(History2(Temp0, Var1))
                                                PRINT Var$;
                                            END IF
                                        END IF
                                    CASE MaxHistory
                                        GOSUB EraseLine
                                        Var$ = RTRIM$(History2(Temp0, MaxHistory))
                                        PRINT Var$;
                                END SELECT
                            END IF
                        CASE 75 ' left
                            GOSUB GetCount
                            IF Var1 > 0 THEN
                                SELECT CASE HistoryCount2(Temp0)
                                    CASE 0
                                        GOSUB EraseLine
                                        HistoryCount2(Temp0) = Var1
                                        Var$ = RTRIM$(History2(Temp0, Var1))
                                        PRINT Var$;
                                    CASE 1
                                        GOSUB EraseLine
                                        Var$ = RTRIM$(History2(Temp0, 1))
                                        PRINT Var$;
                                    CASE ELSE
                                        IF HistoryCount2(Temp0) - 1 > 0 THEN
                                            GOSUB EraseLine
                                            HistoryCount2(Temp0) = HistoryCount2(Temp0) - 1
                                            Var$ = RTRIM$(History2(Temp0, HistoryCount2(Temp0)))
                                            PRINT Var$;
                                        END IF
                                END SELECT
                            END IF
                        CASE 71 ' home
                            GOSUB GetCount
                            IF Var1 > 0 THEN
                                GOSUB EraseLine
                                HistoryCount2(Temp0) = 1
                                Var$ = RTRIM$(History2(Temp0, 1))
                                PRINT Var$;
                            END IF
                        CASE 79 ' end
                            GOSUB GetCount
                            IF Var1 > 0 THEN
                                GOSUB EraseLine
                                HistoryCount2(Temp0) = Var1
                                Var$ = RTRIM$(History2(Temp0, Var1))
                                PRINT Var$;
                            END IF
                    END SELECT
            END SELECT
        END IF
    LOOP

    ' return input line
    KeyboardLine2$ = Var$
    EXIT FUNCTION

    EnterHistory:
    IF LEN(Var$) THEN
        GOSUB GetCount
        ' init
        IF Var1 = 0 THEN
            HistoryCount2(Temp0) = 1
            History2(Temp0, 1) = Var$
        ELSE
            ' add history
            IF HistoryCount2(Temp0) = 0 THEN
                IF Var1 < MaxHistory THEN
                    HistoryCount2(Temp0) = Var1 + 1
                    History2(Temp0, Var1 + 1) = Var$
                ELSE
                    FOR Var = 1 TO MaxHistory - 1
                        History2(Temp0, Var) = History2(Temp0, Var + 1)
                    NEXT
                    HistoryCount2(Temp0) = MaxHistory
                    History2(Temp0, MaxHistory) = Var$
                END IF
            ELSE
                ' pack history
                IF Var1 = MaxHistory THEN
                    FOR Var = HistoryCount2(Temp0) TO MaxHistory - 1
                        History2(Temp0, Var) = History2(Temp0, Var + 1)
                    NEXT
                    HistoryCount2(Temp0) = MaxHistory
                    History2(Temp0, MaxHistory) = Var$
                ELSE
                    FOR Var = HistoryCount2(Temp0) TO Var1 - 1
                        History2(Temp0, Var) = History2(Temp0, Var + 1)
                    NEXT
                    History2(Temp0, Var1) = Var$
                END IF
            END IF
        END IF
    END IF
    RETURN

    EraseLine:
    FOR VarX = 1 TO LEN(Var$)
        GOSUB BackSpace
    NEXT
    Var$ = Nul
    RETURN

    BackSpace:
    IF POS(0) > 1 THEN ' check cursor location
        LOCATE CSRLIN, POS(0) - 1, 0
        PRINT " ";
        LOCATE CSRLIN, POS(0) - 1, Visible
    ELSE ' line-wrap
        LOCATE CSRLIN - 1, ScreenWidth, 0
        PRINT " ";
        LOCATE CSRLIN - 1, ScreenWidth, Visible
    END IF
    RETURN

    GetCount:
    Var1 = 0
    FOR Var2 = MaxHistory TO 1 STEP -1
        IF RTRIM$(History2(Temp0, Var2)) <> Nul THEN
            Var1 = Var2
            EXIT FOR
        END IF
    NEXT
    RETURN
END FUNCTION

' closes last file open,
' resets next free file number
FUNCTION FreeFileNumber
    IF FileNumber THEN
        CLOSE #FileNumber
        FileNumber = False
    END IF
    FileNumber = FREEFILE
    FreeFileNumber = True
END FUNCTION

' set prompts
SUB SetPrompts
    DO
        COLOR White, Black
        PRINT "Edit Prompt Menu:"
        COLOR Yellow, Black
        PRINT "(1)SIC prompt: " + Prompt1
        PRINT "(2)Whatis prompt: " + Prompt2
        PRINT "(3)Debug prompt: " + Prompt3
        DO
            COLOR White, Black
            LOCATE , 1, 1
            PRINT "Enter Prompt(Q To Quit)? ";
            LOCATE , , 1
            LINE INPUT Out2
            IF Out2 = Nul THEN
                EXIT SUB
            END IF
            IF Out2 <> Nul THEN
                EXIT DO
            END IF
        LOOP
        IF UCASE$(Out2) = "Q" THEN
            EXIT DO
        END IF
        COLOR White, Black
        SELECT CASE INT(VAL(Out2))
            CASE 1
                PRINT "SIC Prompt:";
                LINE INPUT Out2
                Prompt1 = Out2
            CASE 2
                PRINT "Whatis Prompt:";
                LINE INPUT Out2
                Prompt2 = Out2
            CASE 3
                PRINT "Debug Prompt:";
                LINE INPUT Out2
                Prompt3 = Out2
        END SELECT
    LOOP
END SUB

' beginning of the command/equation parser
SUB EnterEquate
    ON ERROR GOTO EquateTrap
    AllowExtra = False
    Out2 = STRIM$(Out2)
    IF Out2 = Nul THEN
        EXIT SUB
    END IF
    StoreInput$ = Out2
    CALL Assignment
    IF Assign THEN
        EXIT SUB
    END IF
    Out2 = StoreInput$
    PName$ = UCASE$(Out2)
    FOR PNumber = 1 TO MaxStatements
        SName$ = Statements$(PNumber)
        IF LEFT$(PName$, LEN(SName$)) = SName$ THEN
            IF LEN(PName$) > LEN(SName$) THEN
                IF RIGHT$(SName$, 1) <> "#" THEN
                    BadToken = False
                    TokenForm$ = MID$(PName$, LEN(SName$) + 1, 1)
                    SELECT CASE TokenForm$
                        CASE "(", "[", "{"
                            Token = 2
                        CASE "="
                            IF RIGHT$(SName$, 1) = "$" THEN
                                Token = 1
                            ELSE
                                BadToken = True
                            END IF
                        CASE CHR$(32), CHR$(34) ' space/quote
                            Token = False
                        CASE ELSE
                            BadToken = True
                    END SELECT
                    IF BadToken THEN
                        SELECT CASE PNumber
                            CASE 1, 5, 117 ' rem/data
                                Eat$ = Nul
                            CASE ELSE
                                Strng = "<unknown statement>"
                                ERROR 92
                        END SELECT
                    END IF
                END IF
            END IF
            SELECT CASE PNumber
                CASE 1 ' apostrophe
                    ' (does not exist)
                CASE 2, 3
                    ' Endif/End if
                CASE 4 ' stop
                    ProgramLine = MaxLines
                CASE 5 ' REM
                    Out2 = MID$(Out2, 4)
                    Out2 = STRIM$(Out2)
                    Out2 = UCASE$(Out2)
                    Out2 = TTRIM$(Out2, True)
                    ' REM $metacommand
                    IF LEFT$(Out2, 1) = "$" THEN
                        IF LEFT$(Out2, 9) = "$INCLUDE:" THEN
                            Var$ = MID$(Out2, 10)
                            Var$ = LTRIM$(RTRIM$(Var$))
                            IF LEFT$(Var$, 1) = CHR$(34) AND RIGHT$(Var$, 1) = CHR$(34) THEN
                                Var$ = MID$(Var$, 2)
                                Var$ = LEFT$(Var$, LEN(Var$) - 1)
                                Var$ = Ambiguate$(Var$)
                                Filename = Var$
                                IF _FILEEXISTS(Filename) THEN
                                    CALL ReadProgram
                                    CALL CountLines(LastLine)
                                    EXIT SUB
                                END IF
                            END IF
                            ERROR 53
                            EXIT SUB
                        END IF
                        SELECT CASE Out2
                            CASE "$DEBUG:ON"
                                DebugActive = True
                            CASE "$DEBUG:OFF"
                                DebugActive = False
                            CASE "$LLINES:ON"
                                ListLines = True
                            CASE "$LLINES:OFF"
                                ListLines = False
                            CASE "$DYNAMIC"
                                Eat$ = Nul
                            CASE "$STATIC"
                                Eat$ = Nul
                            CASE ELSE
                                ERROR 160
                                EXIT SUB
                        END SELECT
                    END IF
                CASE 6 ' mid$
                    CALL AssignMidString
                CASE 7 ' left$
                    CALL AssignLeftString
                CASE 8 ' right$
                    CALL AssignRightString
                CASE 9 ' print #
                    ErrorValue = 0
                    CALL PrintExpressionFile
                CASE 10 ' dprint
                    ERROR 73 ' feature unavailable.
                CASE 11 ' lprint using
                    ErrorValue = 0
                    CALL LprintUsing
                CASE 12 ' sprint
                    ErrorValue = 0
                    CALL SprintExpression
                CASE 13 ' uprint
                    ErrorValue = 0
                    CALL UprintExpression
                CASE 14 ' input;
                    CALL InputExpression(1)
                CASE 15 ' forif
                    GOSUB ForifLoop
                CASE 16 ' for
                    GOSUB LoopExpression
                CASE 17 ' nextif
                    GOSUB LoopifTerminate
                CASE 18 ' next
                    GOSUB LoopTerminate
                CASE 19 ' continue for
                    GOSUB ContinueForif
                CASE 20 ' continue forif
                    GOSUB ContinueFor
                CASE 21 ' exit forif
                    GOSUB ExitifFor
                CASE 22 ' exit for
                    GOSUB ExitFor
                CASE 23
                    ' DoUntil
                CASE 24 ' loop while
                    GOSUB EndDoWhile
                CASE 25 ' exit do
                    GOSUB ExitDo
                CASE 26 ' continue do
                    GOSUB ContinueDo
                CASE 27 ' goto
                    GOSUB BranchTo
                CASE 28 ' gosub
                    GOSUB GosubBranch
                CASE 29 ' return
                    GOSUB ReturnBranch
                CASE 30 ' do while
                    GOSUB DoWhile
                CASE 31
                    ' Do
                CASE 32 ' off
                    ProgramLine = MaxLines
                CASE 33 ' if
                    GOSUB IfBranch
                CASE 34 ' elseif
                    GOSUB ElseBranch
                CASE 35 ' caseif else
                    GOSUB SelectifEnd
                CASE 36 ' caseif
                    GOSUB SelectifEnd
                CASE 37 ' select case
                    GOSUB SelectCase
                CASE 38
                    ' End Selectif
                CASE 39 ' beep
                    BEEP
                CASE 40 ' sound
                    CALL SoundSpeaker
                CASE 41 ' color
                    CALL ChangeColor
                CASE 42 ' locate
                    CALL LocateCursor
                CASE 43 ' cls
                    CALL CLSScreen
                CASE 44 ' screen
                    CALL ChangeScreen
                CASE 45 ' width
                    CALL ChangeWidth
                CASE 46 ' write #
                    ErrorValue = 0
                    CALL WriteExpressionFile
                CASE 47 ' line input;
                    CALL LineInputExpression(1)
                CASE 48 ' line input #
                    CALL LineInputExpFile
                CASE 49 ' input #
                    CALL InputExpressionFile
                CASE 50 ' wend
                    GOSUB EndWhile
                CASE 51 ' while
                    GOSUB DoWend
                CASE 52 ' continue while
                    GOSUB ContinueWhile
                CASE 53 ' exit while
                    GOSUB ExitWhile
                CASE 54 ' else
                    GOSUB ElseBranch
                CASE 55 ' loop until
                    GOSUB EndDoUntil
                CASE 56 ' loopif
                    GOSUB LoopifStart
                CASE 57 ' end loopif
                    GOSUB EndloopIf
                CASE 58 ' exit loopif
                    GOSUB ExitloopIf
                CASE 59 ' loop
                    GOSUB EndDo
                CASE 60 ' randmoize
                    CALL SeedRandom
                CASE 61 ' poke
                    CALL PokeValue
                CASE 62 ' int86
                    CALL Int86Function
                CASE 63 ' def seg
                    CALL DefsegFunction
                CASE 64 ' absolute
                    CALL AbsoluteFunction
                CASE 65 ' out
                    CALL OutputPort
                CASE 66 ' wait
                    CALL WaitPort
                CASE 67 ' sleep
                    CALL SleepSecond
                CASE 68 ' pause
                    CALL PauseSecond
                CASE 69 ' selectif case
                    GOSUB SelectifCase
                CASE 70
                    ' End Select
                CASE 71 ' case else
                    GOSUB SelectEnd
                CASE 72 ' case
                    GOSUB SelectEnd
                CASE 73 ' continue loopif
                    GOSUB ContinueLoopif
                CASE 74 ' end
                    ProgramLine = MaxLines
                CASE 75 ' clear
                    ProgramLine = MaxLines
                CASE 76 ' system
                    ProgramLine = MaxLines
                    IF _FILEEXISTS(PrepareFilename) THEN
                        KILL PrepareFilename
                    END IF
                    CALL StopProgram
                CASE 77 ' swap
                    CALL SwapData
                CASE 78 ' error
                    Out2 = MID$(Out2, 6)
                    Out2 = STRIM$(Out2)
                    TokenIndex = 1
                    CALL GetToken
                    CALL Parse1(Temp3#)
                    ERROR CINT(Temp3#)
                CASE 79 ' on error goto
                    Out2 = MID$(Out2, 14)
                    Out2 = STRIM$(Out2)
                    TokenIndex = 1
                    CALL GetToken
                    CALL Parse1(Temp3#)
                    ErrorType = CINT(Temp3#)
                CASE 80 ' on error resume previous
                    ErrorType = -1
                CASE 81 ' on error resume same
                    ErrorType = -2
                CASE 82 ' on error resume next
                    ErrorType = -3
                CASE 83 ' on error stop
                    ErrorType = False
                CASE 84 ' resume previous
                    IF ErrorLine > 0 THEN
                        ProgramLine = ErrorLine - 1
                        DO
                            IF LEN(STRIM$(Program$(ProgramLine))) THEN
                                ProgramLine = ProgramLine - 1
                                EXIT DO
                            END IF
                            ProgramLine = ProgramLine - 1
                            IF ProgramLine < 1 THEN
                                ProgramLine = MaxLines
                                EXIT DO
                            END IF
                        LOOP
                        ErrorLine = 0
                    ELSE
                        ERROR 20
                    END IF
                CASE 85 ' resume same
                    IF ErrorLine > 0 THEN
                        ProgramLine = ErrorLine - 1
                        ErrorLine = 0
                    ELSE
                        ERROR 20
                    END IF
                CASE 86 ' resume next
                    IF ErrorLine > 0 THEN
                        ProgramLine = ErrorLine + 1
                        DO
                            IF LEN(STRIM$(Program$(ProgramLine))) THEN
                                ProgramLine = ProgramLine - 1
                                EXIT DO
                            END IF
                            ProgramLine = ProgramLine + 1
                            IF ProgramLine > LastLine THEN
                                EXIT DO
                            END IF
                        LOOP
                        ErrorLine = 0
                    ELSE
                        ERROR 20
                    END IF
                CASE 87 ' resume
                    IF ErrorLine > 0 THEN
                        Out2 = MID$(Out2, 7)
                        Out2 = STRIM$(Out2)
                        IF Out2 = Nul THEN
                            ProgramLine = ErrorLine - 1
                        ELSE
                            Temp3# = INT(VAL(Out2))
                            IF Temp3# <= 0# THEN
                                ProgramLine = ErrorLine - 1
                            ELSE
                                IF Temp3# <= MaxLines THEN
                                    ProgramLine = CINT(Temp3#) - 1
                                ELSE
                                    ProgramLine = MaxLines
                                END IF
                            END IF
                        END IF
                        ErrorLine = 0
                    ELSE
                        ERROR 20
                    END IF
                CASE 88 ' on x goto/gosub
                    GOSUB MultiBranch
                CASE 89 ' date$=
                    CALL SetDate
                CASE 90 ' time$=
                    CALL SetTime
                CASE 91 ' chdrive
                    ERROR 73 ' feature unavailable.
                CASE 92 ' cd
                    CALL CDDirectory(1)
                CASE 93 ' chdir
                    CALL CDDirectory(2)
                CASE 94 ' md
                    CALL MDDirectory(1)
                CASE 95 ' mkdir
                    CALL MDDirectory(2)
                CASE 96 ' rd
                    CALL RDDirectory(1)
                CASE 97 ' rmdir
                    CALL RDDirectory(2)
                CASE 98 ' kill
                    CALL KillFile(1)
                CASE 99 ' delete
                    CALL KillFile(2)
                CASE 100 ' rename
                    CALL NameExpression(1)
                CASE 101 ' name
                    CALL NameExpression(2)
                CASE 102 ' shell
                    CALL ShellProgram
                CASE 103 ' chain
                    CALL ChainProgram
                CASE 104 ' let
                    CALL AssignKeyword
                CASE 105 ' close #
                    CALL CloseFile(1)
                CASE 106 ' open #
                    CALL OpenFile
                CASE 107 ' field #
                    CALL OpenField
                CASE 108 ' write
                    ErrorValue = 0
                    CALL WriteExpression
                CASE 109 ' print using
                    CALL PrintUsing
                CASE 110 ' input
                    CALL InputExpression(2)
                CASE 111 ' line input
                    CALL LineInputExpression(2)
                CASE 112 ' lset #
                    CALL FieldSet(1)
                CASE 113 ' rset #
                    CALL FieldSet(2)
                CASE 114 ' put #
                    CALL PutRecord
                CASE 115 ' get #
                    CALL GetRecord
                CASE 116 ' read #
                    CALL ReadRecord
                CASE 117
                    ' Data
                CASE 118 ' read
                    CALL ReadData
                CASE 119 ' restore
                    CALL RestoreData
                CASE 120 ' circle step
                    CALL DrawCircleStep
                CASE 121 ' line step
                    CALL DrawLineStep
                CASE 122 ' pset step
                    CALL DrawPixelStep
                CASE 123 ' preset step
                    CALL DrawPixelXStep
                CASE 124 ' paint step
                    CALL PaintAreaStep
                CASE 125 ' draw
                    CALL DrawExpression
                CASE 126 ' play
                    CALL PlayExpression
                CASE 127 ' get step
                    CALL GetGraphicsStep
                CASE 128 ' put step
                    CALL PutGraphicsStep
                CASE 129 ' bsave
                    CALL BSaveImage
                CASE 130 ' bload
                    CALL BLoadImage
                CASE 131 ' view screen
                    CALL ViewScreen(1)
                CASE 132 ' view
                    CALL ViewScreen(2)
                CASE 133 ' window screen
                    CALL WindowScreen(1)
                CASE 134 ' window
                    CALL WindowScreen(2)
                CASE 135 ' circle
                    CALL DrawCircle
                CASE 136 ' line
                    CALL DrawLine
                CASE 137 ' close
                    CALL CloseFile(2)
                CASE 138 ' DEF FN
                    CALL DefineFunction
                CASE 139 ' ENVIRON
                    CALL SetEnviron
                CASE 140 ' paint
                    CALL PaintArea
                CASE 141 ' pset
                    CALL DrawPixel
                CASE 142 ' preset
                    CALL DrawPixelX
                CASE 143 ' get
                    CALL GetGraphics
                CASE 144 ' put
                    CALL PutGraphics
                CASE 145 ' DIM
                    ' doesn't do anything yet
                CASE 146 ' COMMON
                    ' doesn't do anything yet
                CASE 147 ' DECLARE
                    ' doesn't do anything yet
                CASE 148 ' lock
                    CALL LockFile
                CASE 149 ' unlock
                    CALL UnlockFile
                CASE 150 ' print
                    ErrorValue = 0
                    CALL PrintExpression
                CASE 151 ' lprint
                    ErrorValue = 0
                    CALL LprintExpression
                CASE 152 ' triangle
                    CALL DrawTriangle
                CASE 153 ' polygon
                    CALL DrawPolygon
            END SELECT
            EXIT SUB
        END IF
    NEXT
    ERROR 91
    EquateExit:
    EXIT SUB

    ForifLoop:
    Out2 = MID$(Out2, 6)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp4#)
    IF Strng = "," THEN
        IF Temp4# THEN
            Out2 = UCASE$(MID$(Out2, TokenIndex))
            Out2 = STRIM$(Out2)
            Temp1$ = UCASE$(LEFT$(Out2, 1))
            IF Temp1$ >= "A" AND Temp1$ <= "Z" THEN
                Element = ASC(Temp1$) - 64
                Out2 = MID$(Out2, 2)
                Out2 = STRIM$(Out2)
                IF LEFT$(Out2, 1) = "=" THEN
                    Out2 = MID$(Out2, 2)
                    Out2 = STRIM$(Out2)
                    FinishFor = Dfalse
                    StepTo = 1#
                    ExceptStep = Dfalse
                    ExceptStepIs = False
                    CALL Equate(StartFor#)
                    Variables(Element) = StartFor#
                    IF ExceptStepIs THEN
                        IF StartFor# = ExceptStep THEN
                            IF StartFor# = FinishFor THEN
                                GOTO LoopifIgnore
                            ELSE
                                GOSUB LoopifIgnore
                                ProgramLine = ProgramLine - 1
                                RETURN
                            END IF
                        END IF
                    END IF
                    IF StepTo > Dfalse THEN
                        IF StartFor# > FinishFor THEN
                            GOTO LoopifIgnore
                        END IF
                    END IF
                    IF StepTo < Dfalse THEN
                        IF StartFor# < FinishFor THEN
                            GOTO LoopifIgnore
                        END IF
                    END IF
                    RETURN
                END IF
            END IF
        ELSE
            GOTO LoopifIgnore
        END IF
        RETURN
    END IF
    ERROR 103
    RETURN

    LoopifIgnore:
    FOR Count1 = ProgramLine + 1 TO LastLine
        GOSUB ImbeddedifIgnore
        IF Imbedded THEN
            GOTO LoopifIgnore
        END IF
        Temp1$ = Program$(Count1)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 6)) = "NEXTIF" THEN
            ProgramLine = Count1
            RETURN
        END IF
    NEXT
    ERROR 103
    RETURN

    ImbeddedifIgnore:
    Imbedded = False
    Temp1$ = Program$(Count1)
    Temp1$ = STRIM$(Temp1$)
    IF UCASE$(LEFT$(Temp1$, 5)) <> "FORIF" THEN
        RETURN
    END IF
    Imbedded = True
    Nested = 1
    Count2 = Count1
    DO WHILE Count2 < LastLine
        Count2 = Count2 + 1
        Temp1$ = Program$(Count2)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 5)) = "FORIF" THEN
            Nested = Nested + 1
        END IF
        IF UCASE$(LEFT$(Temp1$, 6)) = "NEXTIF" THEN
            Nested = Nested - 1
        END IF
        IF Nested = False THEN
            ProgramLine = Count2
            RETURN
        END IF
    LOOP
    ERROR 103
    RETURN

    LoopifTerminate:
    ForLoop = ProgramLine
    NextifFor:
    FOR Count1 = ProgramLine - 1 TO 1 STEP -1
        GOSUB ImbeddedifFor
        IF Imbedded THEN
            GOTO NextifFor
        END IF
        Temp1$ = Program$(Count1)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 5)) = "FORIF" THEN
            Out2 = MID$(Temp1$, 6)
            Out2 = STRIM$(Out2)
            TokenIndex = 1
            CALL GetToken
            CALL Parse1(Temp4#)
            IF Strng = "," THEN
                IF Temp4# THEN
                    Out2 = UCASE$(MID$(Out2, TokenIndex))
                    Out2 = STRIM$(Out2)
                    Temp1$ = UCASE$(LEFT$(Out2, 1))
                    IF Temp1$ >= "A" AND Temp1$ <= "Z" THEN
                        Element = ASC(Temp1$) - 64
                        Out2 = MID$(Out2, 2)
                        Out2 = STRIM$(Out2)
                        IF LEFT$(Out2, 1) = "=" THEN
                            Out2 = MID$(Out2, 2)
                            Out2 = STRIM$(Out2)
                            FinishFor = Dfalse
                            StepTo = 1#
                            ExceptStep = Dfalse
                            ExceptStepIs = False
                            CALL Equate(X#)
                            Variable# = Variables(Element)
                            Variable# = Variable# + StepTo
                            Variables(Element) = Variable#
                            IF ExceptStepIs THEN
                                IF Variable# = ExceptStep THEN
                                    ProgramLine = ForLoop - 1
                                    RETURN
                                END IF
                            END IF
                            IF StepTo > Dfalse THEN
                                IF Variable# <= FinishFor THEN
                                    ProgramLine = Count1
                                ELSE
                                    ProgramLine = ForLoop
                                END IF
                                RETURN
                            ELSE
                                IF StepTo < Dfalse THEN
                                    IF Variable# >= FinishFor THEN
                                        ProgramLine = Count1
                                    ELSE
                                        ProgramLine = ForLoop
                                    END IF
                                    RETURN
                                END IF
                            END IF
                        END IF
                    END IF
                ELSE
                    ProgramLine = Count1
                END IF
                RETURN
            END IF
            ERROR 103
            RETURN
        END IF
    NEXT
    ERROR 103
    RETURN

    ImbeddedifFor:
    Imbedded = False
    Temp1$ = Program$(Count1)
    Temp1$ = STRIM$(Temp1$)
    IF UCASE$(LEFT$(Temp1$, 6)) <> "NEXTIF" THEN
        RETURN
    END IF
    Imbedded = True
    Nested = 1
    Count2 = Count1
    DO WHILE Count2 > 1
        Count2 = Count2 - 1
        Temp1$ = Program$(Count2)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 6)) = "NEXTIF" THEN
            Nested = Nested + 1
        END IF
        IF UCASE$(LEFT$(Temp1$, 5)) = "FORIF" THEN
            Nested = Nested - 1
        END IF
        IF Nested = False THEN
            ProgramLine = Count2
            RETURN
        END IF
    LOOP
    ERROR 103
    RETURN

    ContinueForif:
    Nested = 1
    Out2 = MID$(Out2, 15)
    Out2 = STRIM$(Out2)
    IF LEN(Out2) THEN
        LastToken = False
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp3#)
        IF Temp3# > Dfalse AND Temp3# <= 255 THEN
            Nested = CINT(Temp3#)
        END IF
    END IF
    FOR Count1 = ProgramLine + 1 TO LastLine
        Temp1$ = Program$(Count1)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 5)) = "FORIF" THEN
            Nested = Nested + 1
        END IF
        IF UCASE$(LEFT$(Temp1$, 6)) = "NEXTIF" THEN
            Nested = Nested - 1
            IF Nested = False THEN
                ProgramLine = Count1 - 1
                RETURN
            END IF
        END IF
    NEXT
    ERROR 103
    RETURN

    ExitifFor:
    Nested = 1
    Out2 = MID$(Out2, 11)
    Out2 = STRIM$(Out2)
    IF LEN(Out2) THEN
        LastToken = False
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp3#)
        IF Temp3# > Dfalse AND Temp3# <= 255 THEN
            Nested = CINT(Temp3#)
        END IF
    END IF
    FOR Count1 = ProgramLine + 1 TO LastLine
        Temp1$ = Program$(Count1)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 5)) = "FORIF" THEN
            Nested = Nested + 1
        END IF
        IF UCASE$(LEFT$(Temp1$, 6)) = "NEXTIF" THEN
            Nested = Nested - 1
            IF Nested = False THEN
                ProgramLine = Count1
                RETURN
            END IF
        END IF
    NEXT
    ERROR 103
    RETURN

    LoopExpression:
    Out2 = MID$(Out2, 4)
    Out2 = STRIM$(Out2)
    Temp1$ = UCASE$(LEFT$(Out2, 1))
    IF Temp1$ >= "A" AND Temp1$ <= "Z" THEN
        Element = ASC(Temp1$) - 64
        Out2 = MID$(Out2, 2)
        Out2 = STRIM$(Out2)
        IF LEFT$(Out2, 1) = "=" THEN
            Out2 = MID$(Out2, 2)
            Out2 = STRIM$(Out2)
            FinishFor = Dfalse
            StepTo = 1#
            ExceptStep = Dfalse
            ExceptStepIs = False
            CALL Equate(StartFor#)
            Variables(Element) = StartFor#
            IF ExceptStepIs THEN
                IF StartFor# = ExceptStep THEN
                    IF StartFor# = FinishFor THEN
                        GOTO LoopIgnore
                    ELSE
                        GOSUB LoopIgnore
                        ProgramLine = ProgramLine - 1
                        RETURN
                    END IF
                END IF
            END IF
            IF StepTo > Dfalse THEN
                IF StartFor# > FinishFor THEN
                    GOTO LoopIgnore
                END IF
            END IF
            IF StepTo < Dfalse THEN
                IF StartFor# < FinishFor THEN
                    GOTO LoopIgnore
                END IF
            END IF
            RETURN
        END IF
    END IF
    ERROR 97
    RETURN

    LoopIgnore:
    FOR Count1 = ProgramLine + 1 TO LastLine
        GOSUB ImbeddedIgnore
        IF Imbedded THEN
            GOTO LoopIgnore
        END IF
        Temp1$ = Program$(Count1)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 4)) = "NEXT" THEN
            IF UCASE$(LEFT$(Temp1$, 6)) <> "NEXTIF" THEN
                ProgramLine = Count1
                RETURN
            END IF
        END IF
    NEXT
    ERROR 97
    RETURN

    ImbeddedIgnore:
    Imbedded = False
    Temp1$ = Program$(Count1)
    Temp1$ = STRIM$(Temp1$)
    IF UCASE$(LEFT$(Temp1$, 5)) <> "FORIF" THEN
        RETURN
    END IF
    IF UCASE$(LEFT$(Temp1$, 3)) <> "FOR" THEN
        RETURN
    END IF
    Imbedded = True
    Nested = 1
    Count2 = Count1
    DO WHILE Count2 < LastLine
        Count2 = Count2 + 1
        Temp1$ = Program$(Count2)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 3)) = "FOR" THEN
            IF UCASE$(LEFT$(Temp1$, 5)) <> "FORIF" THEN
                Nested = Nested + 1
            END IF
        END IF
        IF UCASE$(LEFT$(Temp1$, 4)) = "NEXT" THEN
            IF UCASE$(LEFT$(Temp1$, 6)) <> "NEXTIF" THEN
                Nested = Nested - 1
            END IF
        END IF
        IF Nested = False THEN
            ProgramLine = Count2
            RETURN
        END IF
    LOOP
    ERROR 97
    RETURN

    LoopTerminate:
    ForLoop = ProgramLine
    NextFor:
    FOR Count1 = ProgramLine - 1 TO 1 STEP -1
        GOSUB Imbedded.For
        IF Imbedded THEN
            GOTO NextFor
        END IF
        Temp1$ = Program$(Count1)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 3)) = "FOR" THEN
            IF UCASE$(LEFT$(Temp1$, 5)) <> "FORIF" THEN
                Temp1$ = MID$(Temp1$, 4)
                Temp1$ = STRIM$(Temp1$)
                Temp2$ = UCASE$(LEFT$(Temp1$, 1))
                IF Temp2$ >= "A" AND Temp2$ <= "Z" THEN
                    Element = ASC(Temp2$) - 64
                    Out2 = MID$(Temp1$, 2)
                    Out2 = STRIM$(Out2)
                    IF LEFT$(Out2, 1) = "=" THEN
                        Out2 = MID$(Out2, 2)
                        Out2 = STRIM$(Out2)
                        FinishFor = Dfalse
                        StepTo = 1#
                        ExceptStep = Dfalse
                        ExceptStepIs = False
                        CALL Equate(X#)
                        Variable# = Variables(Element)
                        Variable# = Variable# + StepTo
                        Variables(Element) = Variable#
                        IF ExceptStepIs THEN
                            IF Variable# = ExceptStep THEN
                                ProgramLine = ForLoop - 1
                                RETURN
                            END IF
                        END IF
                        IF StepTo > Dfalse THEN
                            IF Variable# <= FinishFor THEN
                                ProgramLine = Count1
                            ELSE
                                ProgramLine = ForLoop
                            END IF
                            RETURN
                        ELSE
                            IF StepTo < Dfalse THEN
                                IF Variable# >= FinishFor THEN
                                    ProgramLine = Count1
                                ELSE
                                    ProgramLine = ForLoop
                                END IF
                                RETURN
                            END IF
                        END IF
                    END IF
                END IF
            END IF
        END IF
    NEXT
    ERROR 97
    RETURN

    Imbedded.For:
    Imbedded = False
    Temp1$ = Program$(Count1)
    Temp1$ = STRIM$(Temp1$)
    IF UCASE$(LEFT$(Temp1$, 6)) = "NEXTIF" THEN
        RETURN
    END IF
    IF UCASE$(LEFT$(Temp1$, 4)) <> "NEXT" THEN
        RETURN
    END IF
    Imbedded = True
    Nested = 1
    Count2 = Count1
    DO WHILE Count2 > 1
        Count2 = Count2 - 1
        Temp1$ = Program$(Count2)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 4)) = "NEXT" THEN
            IF UCASE$(LEFT$(Temp1$, 6)) <> "NEXTIF" THEN
                Nested = Nested + 1
            END IF
        END IF
        IF UCASE$(LEFT$(Temp1$, 3)) = "FOR" THEN
            IF UCASE$(LEFT$(Temp1$, 5)) <> "FORIF" THEN
                Nested = Nested - 1
            END IF
        END IF
        IF Nested = False THEN
            ProgramLine = Count2
            RETURN
        END IF
    LOOP
    ERROR 97
    RETURN

    ContinueFor:
    Nested = 1
    Out2 = MID$(Out2, 13)
    Out2 = STRIM$(Out2)
    IF LEN(Out2) THEN
        LastToken = False
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp3#)
        IF Temp3# > Dfalse AND Temp3# <= 255 THEN
            Nested = CINT(Temp3#)
        END IF
    END IF
    FOR Count1 = ProgramLine + 1 TO LastLine
        Temp1$ = Program$(Count1)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 3)) = "FOR" THEN
            IF UCASE$(LEFT$(Temp1$, 5)) <> "FORIF" THEN
                Nested = Nested + 1
            END IF
        END IF
        IF UCASE$(LEFT$(Temp1$, 4)) = "NEXT" THEN
            IF UCASE$(LEFT$(Temp1$, 6)) <> "NEXTIF" THEN
                Nested = Nested - 1
                IF Nested = False THEN
                    ProgramLine = Count1 - 1
                    RETURN
                END IF
            END IF
        END IF
    NEXT
    ERROR 97
    RETURN

    ExitFor:
    Nested = 1
    Out2 = MID$(Out2, 9)
    Out2 = STRIM$(Out2)
    IF LEN(Out2) THEN
        LastToken = False
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp3#)
        IF Temp3# > Dfalse AND Temp3# <= 255 THEN
            Nested = CINT(Temp3#)
        END IF
    END IF
    FOR Count1 = ProgramLine + 1 TO LastLine
        Temp1$ = Program$(Count1)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 3)) = "FOR" THEN
            IF UCASE$(LEFT$(Temp1$, 5)) <> "FORIF" THEN
                Nested = Nested + 1
            END IF
        END IF
        IF UCASE$(LEFT$(Temp1$, 4)) = "NEXT" THEN
            IF UCASE$(LEFT$(Temp1$, 6)) <> "NEXTIF" THEN
                Nested = Nested - 1
                IF Nested = False THEN
                    ProgramLine = Count1
                    RETURN
                END IF
            END IF
        END IF
    NEXT
    ERROR 97
    RETURN

    EndDoWhile:
    Out2 = MID$(Out2, 11)
    Out2 = STRIM$(Out2)
    CALL Equate(Temp3#)
    IF Temp3# = Dtrue THEN
        GOTO EndDo
    END IF
    RETURN

    EndDoUntil:
    Out2 = MID$(Out2, 11)
    Out2 = STRIM$(Out2)
    CALL Equate(Temp3#)
    IF Temp3# = Dfalse THEN
        GOTO EndDo
    END IF
    RETURN

    EndDo:
    LoopLine = ProgramLine

    NextDo:
    FOR Count1 = ProgramLine - 1 TO 1 STEP -1
        GOSUB ImbeddedLoop
        IF Imbedded THEN
            GOTO NextDo
        END IF
        Temp1$ = STRIM$(Program$(Count1))
        IF UCASE$(LEFT$(Temp1$, 2)) = "DO" THEN
            IF UCASE$(LEFT$(Temp1$, 8)) = "DO WHILE" THEN
                Out2 = MID$(Temp1$, 9)
                Out2 = STRIM$(Out2)
                CALL Equate(Temp3#)
                IF Temp3# = Dfalse THEN
                    ProgramLine = LoopLine
                ELSE
                    ProgramLine = Count1
                END IF
                RETURN
            ELSE
                IF UCASE$(LEFT$(Temp1$, 8)) = "DO UNTIL" THEN
                    Out2 = MID$(Temp1$, 9)
                    Out2 = STRIM$(Out2)
                    CALL Equate(Temp3#)
                    IF Temp3# <> Dfalse THEN
                        ProgramLine = LoopLine
                    ELSE
                        ProgramLine = Count1
                    END IF
                    RETURN
                ELSE
                    ProgramLine = Count1
                    RETURN
                END IF
            END IF
        END IF
    NEXT
    ERROR 98
    RETURN

    LoopifStart:
    UnlessBranch = False
    Out2 = MID$(Out2, 7)
    Out2 = STRIM$(Out2)
    IF Out2 = Nul THEN
        ERROR 104
    END IF
    CALL Equate(Temp3#)
    IF Temp3# THEN
        IF UnlessBranch = False THEN
            RETURN
        ELSE
            IF UnlessValue = Dfalse THEN
                RETURN
            END IF
        END IF
    END IF
    Nested = 1
    FOR Count1 = ProgramLine + 1 TO LastLine
        Temp1$ = Program$(Count1)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 6)) = "LOOPIF" THEN
            Nested = Nested + 1
        END IF
        IF UCASE$(LEFT$(Temp1$, 10)) = "END LOOPIF" THEN
            Nested = Nested - 1
            IF Nested = False THEN
                ProgramLine = Count1
                RETURN
            END IF
        END IF
    NEXT
    ERROR 104
    RETURN

    EndloopIf:
    LoopLine = ProgramLine
    NextIfdo:
    FOR Count1 = ProgramLine - 1 TO 1 STEP -1
        GOSUB ImbeddedLoopif
        IF Imbedded THEN
            GOTO NextIfdo
        END IF
        Temp1$ = STRIM$(Program$(Count1))
        IF UCASE$(LEFT$(Temp1$, 6)) = "LOOPIF" THEN
            Out2 = MID$(Temp1$, 7)
            Out2 = STRIM$(Out2)
            CALL Equate(Temp3#)
            IF Temp3# = Dfalse THEN
                ProgramLine = LoopLine
            ELSE
                ProgramLine = Count1
            END IF
            RETURN
        END IF
    NEXT
    ERROR 104
    RETURN

    ExitloopIf:
    Nested = 1
    Out2 = MID$(Out2, 12)
    Out2 = STRIM$(Out2)
    IF LEN(Out2) THEN
        LastToken = False
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp3#)
        IF Temp3# > Dfalse AND Temp3# <= 255 THEN
            Nested = CINT(Temp3#)
        END IF
    END IF
    FOR Count1 = ProgramLine + 1 TO LastLine
        Temp1$ = Program$(Count1)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 6)) = "LOOPIF" THEN
            Nested = Nested + 1
        END IF
        IF UCASE$(LEFT$(Temp1$, 10)) = "END LOOPIF" THEN
            Nested = Nested - 1
            IF Nested = False THEN
                ProgramLine = Count1
                RETURN
            END IF
        END IF
    NEXT
    ERROR 104
    RETURN

    ImbeddedLoopif:
    Imbedded = False
    Temp1$ = Program$(Count1)
    Temp1$ = STRIM$(Temp1$)
    IF UCASE$(LEFT$(Temp1$, 10)) <> "END LOOPIF" THEN
        RETURN
    END IF
    Imbedded = True
    Nested = 1
    Count2 = Count1
    DO WHILE Count2 > 1
        Count2 = Count2 - 1
        Temp1$ = Program$(Count2)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 10)) = "END LOOPIF" THEN
            Nested = Nested + 1
        END IF
        IF UCASE$(LEFT$(Temp1$, 6)) = "LOOPIF" THEN
            Nested = Nested - 1
        END IF
        IF Nested = False THEN
            ProgramLine = Count2
            RETURN
        END IF
    LOOP
    ERROR 104
    RETURN

    ContinueLoopif:
    Nested = 1
    Out2 = MID$(Out2, 16)
    Out2 = STRIM$(Out2)
    IF LEN(Out2) THEN
        LastToken = False
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp3#)
        IF Temp3# > Dfalse AND Temp3# <= 255 THEN
            Nested = CINT(Temp3#)
        END IF
    END IF
    FOR Count1 = ProgramLine + 1 TO LastLine
        Temp1$ = Program$(Count1)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 6)) = "LOOPIF" THEN
            Nested = Nested + 1
        END IF
        IF UCASE$(LEFT$(Temp1$, 10)) = "END LOOPIF" THEN
            Nested = Nested - 1
            IF Nested = False THEN
                ProgramLine = Count1 - 1
                RETURN
            END IF
        END IF
    NEXT
    ERROR 104
    RETURN

    ImbeddedLoop:
    Imbedded = False
    Temp1$ = Program$(Count1)
    Temp1$ = STRIM$(Temp1$)
    IF UCASE$(LEFT$(Temp1$, 6)) = "LOOPIF" THEN
        RETURN
    END IF
    IF UCASE$(LEFT$(Temp1$, 4)) <> "LOOP" THEN
        RETURN
    END IF
    Imbedded = True
    Nested = 1
    Count2 = Count1
    DO WHILE Count2 > 1
        Count2 = Count2 - 1
        Temp1$ = Program$(Count2)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 4)) = "LOOP" THEN
            IF UCASE$(LEFT$(Temp1$, 6)) <> "LOOPIF" THEN
                Nested = Nested + 1
            END IF
        END IF
        IF UCASE$(LEFT$(Temp1$, 2)) = "DO" THEN
            Nested = Nested - 1
        END IF
        IF Nested = False THEN
            ProgramLine = Count2
            RETURN
        END IF
    LOOP
    ERROR 98
    RETURN

    ContinueDo:
    Nested = 1
    Out2 = MID$(Out2, 12)
    Out2 = STRIM$(Out2)
    IF LEN(Out2) THEN
        LastToken = False
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp3#)
        IF Temp3# > Dfalse AND Temp3# <= 255 THEN
            Nested = CINT(Temp3#)
        END IF
    END IF
    FOR Count1 = ProgramLine + 1 TO LastLine
        Temp1$ = Program$(Count1)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 2)) = "DO" THEN
            Nested = Nested + 1
        END IF
        IF UCASE$(LEFT$(Temp1$, 4)) = "LOOP" THEN
            IF UCASE$(LEFT$(Temp1$, 6)) <> "LOOPIF" THEN
                Nested = Nested - 1
                IF Nested = False THEN
                    ProgramLine = Count1 - 1
                    RETURN
                END IF
            END IF
        END IF
    NEXT
    ERROR 98
    RETURN

    ExitDo:
    Nested = 1
    Out2 = MID$(Out2, 8)
    Out2 = STRIM$(Out2)
    IF LEN(Out2) THEN
        LastToken = False
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp3#)
        IF Temp3# > Dfalse AND Temp3# <= 255 THEN
            Nested = CINT(Temp3#)
        END IF
    END IF
    FOR Count1 = ProgramLine + 1 TO LastLine
        Temp1$ = Program$(Count1)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 2)) = "DO" THEN
            Nested = Nested + 1
        END IF
        IF UCASE$(LEFT$(Temp1$, 4)) = "LOOP" THEN
            IF UCASE$(LEFT$(Temp1$, 6)) <> "LOOPIF" THEN
                Nested = Nested - 1
                IF Nested = False THEN
                    ProgramLine = Count1
                    RETURN
                END IF
            END IF
        END IF
    NEXT
    ERROR 98
    RETURN

    BranchTo:
    Out2 = MID$(Out2, 5)
    Out2 = STRIM$(Out2)
    CALL Equate(Temp3#)
    BranchLoop = CINT(Temp3#)
    IF BranchLoop > False AND BranchLoop <= LastLine THEN
        Temp1$ = STRIM$(Program$(BranchLoop))
        IF Temp1$ <> Nul THEN
            ProgramLine = BranchLoop - 1
            RETURN
        END IF
    END IF
    ERROR 99
    RETURN

    GosubBranch:
    Out2 = MID$(Out2, 6)
    Out2 = STRIM$(Out2)
    CALL Equate(Temp3#)
    BranchLoop = CINT(Temp3#)
    IF BranchLoop > False AND BranchLoop <= LastLine THEN
        Temp1$ = STRIM$(Program$(BranchLoop))
        IF Temp1$ <> Nul THEN
            NestedGosub = NestedGosub + 1
            IF NestedGosub = MaxGosubs THEN
                MaxGosubs = MaxGosubs + 1
                REDIM _PRESERVE GosubReturn(1 TO MaxGosubs) AS INTEGER
            END IF
            IF NestedGosub >= MaxNestGosub THEN
                ERROR 156
                EXIT SUB
            END IF
            GosubReturn(NestedGosub) = ProgramLine
            ProgramLine = BranchLoop - 1
            RETURN
        END IF
    END IF
    ERROR 99
    RETURN

    ReturnBranch:
    IF NestedGosub > False THEN
        ProgramLine = GosubReturn(NestedGosub)
        NestedGosub = NestedGosub - 1
        RETURN
    END IF
    ERROR 100
    RETURN

    DoWhile:
    Out2 = MID$(Out2, 9)
    Out2 = STRIM$(Out2)
    CALL Equate(Temp3#)
    IF Temp3# = Dfalse THEN
        DoBranch:
        FOR Count1 = ProgramLine + 1 TO LastLine
            GOSUB Imbedded.Do
            IF Imbedded THEN
                GOTO DoBranch
            END IF
            Temp1$ = Program$(Count1)
            Temp1$ = STRIM$(Temp1$)
            IF UCASE$(LEFT$(Temp1$, 4)) = "LOOP" THEN
                IF UCASE$(LEFT$(Temp1$, 6)) <> "LOOPIF" THEN
                    ProgramLine = Count1
                    RETURN
                END IF
            END IF
        NEXT
        ERROR 98
    END IF
    RETURN

    Imbedded.Do:
    Imbedded = False
    Temp1$ = Program$(Count1)
    Temp1$ = STRIM$(Temp1$)
    IF UCASE$(LEFT$(Temp1$, 2)) <> "DO" THEN
        RETURN
    END IF
    Imbedded = True
    Nested = 1
    Count2 = Count1
    DO WHILE Count2 < LastLine
        Count2 = Count2 + 1
        Temp1$ = Program$(Count2)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 2)) = "DO" THEN
            Nested = Nested + 1
        END IF
        IF UCASE$(LEFT$(Temp1$, 4)) = "LOOP" THEN
            IF UCASE$(LEFT$(Temp1$, 6)) <> "LOOPIF" THEN
                Nested = Nested - 1
            END IF
        END IF
        IF Nested = False THEN
            ProgramLine = Count2
            RETURN
        END IF
    LOOP
    ERROR 98
    RETURN

    MultiBranch:
    Out2 = MID$(Out2, 3)
    Out2 = STRIM$(Out2)
    BranchIndex = False
    BranchNumber = False
    BranchType = False
    NextBranch = INSTR(UCASE$(Out2), "GOTO")
    IF NextBranch THEN
        BranchType = 1
        OutX$ = MID$(Out2, NextBranch + 4)
        Out2 = LEFT$(Out2, NextBranch - 1)
    ELSE
        NextBranch = INSTR(UCASE$(Out2), "GOSUB")
        IF NextBranch THEN
            BranchType = 2
            OutX$ = MID$(Out2, NextBranch + 5)
            Out2 = LEFT$(Out2, NextBranch - 1)
        END IF
    END IF
    IF BranchType = False THEN
        ERROR 99
    END IF
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    BranchIndex = CINT(Temp3#)
    IF BranchIndex <= False THEN
        EXIT SUB
    END IF
    IF BranchType = 1 THEN
        TokenIndex = 1
        Out2 = OutX$
        CALL GetToken
        CALL Parse1(Temp4#)
        FOR IndexCount = 1 TO BranchIndex - 1
            IF Strng <> "," THEN
                Temp4# = Dfalse
                EXIT FOR
            END IF
            CALL GetToken
            CALL Parse1(Temp4#)
        NEXT
        BranchNumber = CINT(Temp4#)
        IF BranchNumber = False THEN
            RETURN
        END IF
        IF BranchNumber > False AND BranchNumber <= LastLine THEN
            Temp1$ = STRIM$(Program$(BranchNumber))
            IF Temp1$ <> Nul THEN
                ProgramLine = BranchNumber - 1
                RETURN
            END IF
        END IF
    ELSE
        IF BranchType = 2 THEN
            TokenIndex = 1
            Out2 = OutX$
            CALL GetToken
            CALL Parse1(Temp4#)
            FOR IndexCount = 1 TO BranchIndex - 1
                IF Strng <> "," THEN
                    Temp4# = Dfalse
                    EXIT FOR
                END IF
                CALL GetToken
                CALL Parse1(Temp4#)
            NEXT
            BranchNumber = CINT(Temp4#)
            IF BranchNumber = False THEN
                RETURN
            END IF
            IF BranchNumber > False AND BranchNumber <= LastLine THEN
                Temp1$ = STRIM$(Program$(BranchNumber))
                IF Temp1$ <> Nul THEN
                    NestedGosub = NestedGosub + 1
                    IF NestedGosub = MaxGosubs THEN
                        MaxGosubs = MaxGosubs + 1
                        REDIM _PRESERVE GosubReturn(1 TO MaxGosubs) AS INTEGER
                    END IF
                    IF NestedGosub >= MaxNestGosub THEN
                        ERROR 156
                        EXIT SUB
                    END IF
                    GosubReturn(NestedGosub) = ProgramLine
                    ProgramLine = BranchNumber - 1
                    RETURN
                END IF
            END IF
        END IF
    END IF
    ERROR 99
    RETURN

    IfBranch:
    UnlessBranch = False
    Out2 = MID$(Out2, 3)
    Out2 = STRIM$(Out2)
    CALL Equate(Temp3#)
    IF Temp3# THEN
        IF UnlessBranch = False THEN
            RETURN
        ELSE
            IF UnlessValue = Dfalse THEN
                RETURN
            END IF
        END IF
    END IF
    EndifBranch:
    FOR Count1 = ProgramLine + 1 TO LastLine
        GOSUB ImbeddedEndif
        IF Imbedded THEN
            GOTO EndifBranch
        END IF
        Temp1$ = Program$(Count1)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 6)) = "ELSEIF" THEN
            ProgramLine = Count1
            Out2 = UCASE$(MID$(Temp1$, 5))
            GOTO IfBranch
            RETURN
        END IF
        IF UCASE$(LEFT$(Temp1$, 4)) = "ELSE" THEN
            ProgramLine = Count1
            RETURN
        END IF
        IF UCASE$(LEFT$(Temp1$, 5)) = "ENDIF" OR UCASE$(LEFT$(Temp1$, 6)) = "END IF" THEN
            ProgramLine = Count1
            RETURN
        END IF
    NEXT
    ERROR 99
    RETURN

    ElseBranch:
    FOR Count1 = ProgramLine + 1 TO LastLine
        GOSUB ImbeddedEndif
        IF Imbedded THEN
            GOTO ElseBranch
        END IF
        Temp1$ = Program$(Count1)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 5)) = "ENDIF" OR UCASE$(LEFT$(Temp1$, 6)) = "END IF" THEN
            ProgramLine = Count1
            RETURN
        END IF
    NEXT
    ERROR 99
    RETURN

    ImbeddedEndif:
    Imbedded = False
    Temp1$ = Program$(Count1)
    Temp1$ = STRIM$(Temp1$)
    IF UCASE$(LEFT$(Temp1$, 2)) <> "IF" THEN
        RETURN
    END IF
    Imbedded = True
    Nested = 1
    Count2 = Count1
    DO WHILE Count2 < LastLine
        Count2 = Count2 + 1
        Temp1$ = Program$(Count2)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 2)) = "IF" THEN
            Nested = Nested + 1
        END IF
        IF UCASE$(LEFT$(Temp1$, 5)) = "ENDIF" OR UCASE$(LEFT$(Temp1$, 6)) = "END IF" THEN
            Nested = Nested - 1
        END IF
        IF Nested = False THEN
            ProgramLine = Count2
            RETURN
        END IF
    LOOP
    ERROR 99
    RETURN

    DoWend:
    Out2 = MID$(Out2, 6)
    Out2 = STRIM$(Out2)
    CALL Equate(Temp3#)
    IF Temp3# = Dfalse THEN
        WhileBranch:
        FOR Count1 = ProgramLine + 1 TO LastLine
            GOSUB ImbeddedWend
            IF Imbedded THEN
                GOTO WhileBranch
            END IF
            Temp1$ = Program$(Count1)
            Temp1$ = STRIM$(Temp1$)
            IF UCASE$(LEFT$(Temp1$, 4)) = "WEND" THEN
                ProgramLine = Count1
                RETURN
            END IF
        NEXT
        ERROR 98
    END IF
    RETURN

    ImbeddedWend:
    Imbedded = False
    Temp1$ = Program$(Count1)
    Temp1$ = STRIM$(Temp1$)
    IF UCASE$(LEFT$(Temp1$, 5)) <> "WHILE" THEN
        RETURN
    END IF
    Imbedded = True
    Nested = 1
    Count2 = Count1
    DO WHILE Count2 < LastLine
        Count2 = Count2 + 1
        Temp1$ = Program$(Count2)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 5)) = "WHILE" THEN
            Nested = Nested + 1
        END IF
        IF UCASE$(LEFT$(Temp1$, 4)) = "WEND" THEN
            Nested = Nested - 1
        END IF
        IF Nested = False THEN
            ProgramLine = Count2
            RETURN
        END IF
    LOOP
    ERROR 98
    RETURN

    EndWhile:
    LoopLine = ProgramLine
    NextWhile:
    FOR Count1 = ProgramLine - 1 TO 1 STEP -1
        GOSUB ImbeddedWhile
        IF Imbedded THEN
            GOTO NextWhile
        END IF
        Temp1$ = STRIM$(Program$(Count1))
        IF UCASE$(LEFT$(Temp1$, 5)) = "WHILE" THEN
            Out2 = MID$(Temp1$, 6)
            Out2 = STRIM$(Out2)
            CALL Equate(Temp3#)
            IF Temp3# = Dfalse THEN
                ProgramLine = LoopLine
            ELSE
                ProgramLine = Count1
            END IF
            RETURN
        END IF
    NEXT
    ERROR 98
    RETURN

    ImbeddedWhile:
    Imbedded = False
    Temp1$ = Program$(Count1)
    Temp1$ = STRIM$(Temp1$)
    IF UCASE$(LEFT$(Temp1$, 4)) <> "WEND" THEN
        RETURN
    END IF
    Imbedded = True
    Nested = 1
    Count2 = Count1
    DO WHILE Count2 > 1
        Count2 = Count2 - 1
        Temp1$ = Program$(Count2)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 4)) = "WEND" THEN
            Nested = Nested + 1
        END IF
        IF UCASE$(LEFT$(Temp1$, 5)) = "WHILE" THEN
            Nested = Nested - 1
        END IF
        IF Nested = False THEN
            ProgramLine = Count2
            RETURN
        END IF
    LOOP
    ERROR 98
    RETURN

    ContinueWhile:
    Nested = 1
    Out2 = MID$(Out2, 15)
    Out2 = STRIM$(Out2)
    IF LEN(Out2) THEN
        LastToken = False
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp3#)
        IF Temp3# > Dfalse AND Temp3# <= 255 THEN
            Nested = CINT(Temp3#)
        END IF
    END IF
    FOR Count1 = ProgramLine + 1 TO LastLine
        Temp1$ = Program$(Count1)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 5)) = "WHILE" THEN
            Nested = Nested + 1
        END IF
        IF UCASE$(LEFT$(Temp1$, 4)) = "WEND" THEN
            Nested = Nested - 1
            IF Nested = False THEN
                ProgramLine = Count1 - 1
                RETURN
            END IF
        END IF
    NEXT
    ERROR 98
    RETURN

    ExitWhile:
    Nested = 1
    Out2 = MID$(Out2, 11)
    Out2 = STRIM$(Out2)
    IF LEN(Out2) THEN
        LastToken = False
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp3#)
        IF Temp3# > Dfalse AND Temp3# <= 255 THEN
            Nested = CINT(Temp3#)
        END IF
    END IF
    FOR Count1 = ProgramLine + 1 TO LastLine
        Temp1$ = Program$(Count1)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 5)) = "WHILE" THEN
            Nested = Nested + 1
        END IF
        IF UCASE$(LEFT$(Temp1$, 4)) = "WEND" THEN
            Nested = Nested - 1
            IF Nested = False THEN
                ProgramLine = Count1
                RETURN
            END IF
        END IF
    NEXT
    ERROR 98
    RETURN

    SelectEnd:
    FOR Count1 = ProgramLine + 1 TO LastLine
        GOSUB ImbeddedSelect
        IF Imbedded THEN
            GOTO SelectEnd
        END IF
        Temp1$ = Program$(Count1)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 12)) <> "END SELECTIF" THEN
            IF UCASE$(LEFT$(Temp1$, 10)) = "END SELECT" THEN
                ProgramLine = Count1
                RETURN
            END IF
        END IF
    NEXT
    ERROR 102
    RETURN

    SelectifEnd:
    FOR Count1 = ProgramLine + 1 TO LastLine
        GOSUB ImbeddedifSelect
        IF Imbedded THEN
            GOTO SelectifEnd
        END IF
        Temp1$ = Program$(Count1)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 12)) = "END SELECTIF" THEN
            ProgramLine = Count1
            RETURN
        END IF
    NEXT
    ERROR 105
    RETURN

    SelectCase:
    LastToken = False
    Out2 = MID$(Out2, 12)
    CALL Equate(Temp3#)
    IF LastToken THEN
        CaseValue = Temp3#
    ELSE
        CaseStrng = Out3
    END IF
    PreviousToken = LastToken
    NextSelectCase:
    FOR Count1 = ProgramLine + 1 TO LastLine
        GOSUB ImbeddedSelect
        IF Imbedded THEN
            GOTO NextSelectCase
        END IF
        Temp1$ = Program$(Count1)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 12)) <> "END SELECTIF" THEN
            IF UCASE$(LEFT$(Temp1$, 10)) = "END SELECT" THEN
                ProgramLine = Count1
                RETURN
            END IF
        END IF
        IF UCASE$(LEFT$(Temp1$, 9)) = "CASE ELSE" THEN
            ProgramLine = Count1
            RETURN
        END IF
        IF UCASE$(LEFT$(Temp1$, 6)) <> "CASEIF" THEN
            IF UCASE$(LEFT$(Temp1$, 4)) = "CASE" THEN
                Out2 = MID$(Temp1$, 5)
                Out2 = STRIM$(Out2)
                TokenIndex = 1
                DO
                    IF LastToken <> 1 THEN
                        LastToken = False
                        CALL GetToken
                    END IF
                    CALL Parse1(Temp4#)
                    SELECT CASE LastToken
                        CASE -1
                            IF CaseValue = Temp4# THEN
                                ProgramLine = Count1
                                RETURN
                            END IF
                        CASE 0
                            IF CaseStrng = Out3 THEN
                                ProgramLine = Count1
                                RETURN
                            END IF
                        CASE 1
                            IF ValueIs THEN
                                ProgramLine = Count1
                                RETURN
                            END IF
                        CASE 2
                            IF PreviousToken THEN
                                IF CaseValue >= CaseValue1 AND CaseValue <= CaseValue2 THEN
                                    ProgramLine = Count1
                                    RETURN
                                END IF
                            ELSE
                                IF CaseStrng >= CaseValueS1 AND CaseStrng <= CaseValueS2 THEN
                                    ProgramLine = Count1
                                    RETURN
                                END IF
                            END IF
                    END SELECT
                    IF TokenIndex > LEN(Out2) THEN
                        EXIT DO
                    END IF
                LOOP
            END IF
        END IF
    NEXT
    ERROR 102
    RETURN

    SelectifCase:
    Out2 = MID$(Out2, 14)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp4#)
    IF Strng = "," THEN
        IF Temp4# THEN
            Out2 = UCASE$(MID$(Out2, TokenIndex))
            Out2 = STRIM$(Out2)
            LastToken = False
            CALL Equate(Temp3#)
            IF LastToken THEN
                CaseValue = Temp3#
            ELSE
                CaseStrng = Out3
            END IF
            PreviousToken = LastToken
            NextSelectifCase:
            FOR Count1 = ProgramLine + 1 TO LastLine
                GOSUB ImbeddedifSelect
                IF Imbedded THEN
                    GOTO NextSelectifCase
                END IF
                Temp1$ = Program$(Count1)
                Temp1$ = STRIM$(Temp1$)
                IF UCASE$(LEFT$(Temp1$, 12)) = "END SELECTIF" THEN
                    ProgramLine = Count1
                    RETURN
                END IF
                IF UCASE$(LEFT$(Temp1$, 11)) = "CASEIF ELSE" THEN
                    ProgramLine = Count1
                    RETURN
                END IF
                IF UCASE$(LEFT$(Temp1$, 6)) = "CASEIF" THEN
                    Out2 = MID$(Temp1$, 7)
                    Out2 = STRIM$(Out2)
                    TokenIndex = 1
                    DO
                        IF LastToken <> 1 THEN
                            LastToken = False
                            CALL GetToken
                        END IF
                        CALL Parse1(Temp4#)
                        SELECT CASE LastToken
                            CASE -1
                                IF CaseValue = Temp4# THEN
                                    ProgramLine = Count1
                                    RETURN
                                END IF
                            CASE 0
                                IF CaseStrng = Out3 THEN
                                    ProgramLine = Count1
                                    RETURN
                                END IF
                            CASE 1
                                IF ValueIs THEN
                                    ProgramLine = Count1
                                    RETURN
                                END IF
                            CASE 2
                                IF PreviousToken THEN
                                    IF CaseValue >= CaseValue1 AND CaseValue <= CaseValue2 THEN
                                        ProgramLine = Count1
                                        RETURN
                                    END IF
                                ELSE
                                    IF CaseStrng >= CaseValueS1 AND CaseStrng <= CaseValueS2 THEN
                                        ProgramLine = Count1
                                        RETURN
                                    END IF
                                END IF
                        END SELECT
                        IF TokenIndex > LEN(Out2) THEN
                            EXIT DO
                        END IF
                    LOOP
                END IF
            NEXT
        ELSE
            GOTO SelectifIgnore
        END IF
        RETURN
    END IF
    ERROR 105
    RETURN

    SelectifIgnore:
    FOR Count1 = ProgramLine + 1 TO LastLine
        GOSUB ImbeddedselectifIgnore
        IF Imbedded THEN
            GOTO SelectifIgnore
        END IF
        Temp1$ = Program$(Count1)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 12)) = "END SELECTIF" THEN
            ProgramLine = Count1
            RETURN
        END IF
    NEXT
    ERROR 105
    RETURN

    ImbeddedselectifIgnore:
    Imbedded = False
    Temp1$ = Program$(Count1)
    Temp1$ = STRIM$(Temp1$)
    IF UCASE$(LEFT$(Temp1$, 13)) <> "SELECTIF CASE" THEN
        RETURN
    END IF
    Imbedded = True
    Nested = 1
    Count2 = Count1
    DO WHILE Count2 < LastLine
        Count2 = Count2 + 1
        Temp1$ = Program$(Count2)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 5)) = "SELECTIF CASE" THEN
            Nested = Nested + 1
        END IF
        IF UCASE$(LEFT$(Temp1$, 6)) = "END SELECTIF" THEN
            Nested = Nested - 1
        END IF
        IF Nested = False THEN
            ProgramLine = Count2
            RETURN
        END IF
    LOOP
    ERROR 105
    RETURN

    ImbeddedSelect:
    Imbedded = False
    Temp1$ = Program$(Count1)
    Temp1$ = STRIM$(Temp1$)
    IF UCASE$(LEFT$(Temp1$, 11)) <> "SELECT CASE" THEN
        RETURN
    END IF
    Imbedded = True
    Nested = 1
    Count2 = Count1
    DO WHILE Count2 < LastLine
        Count2 = Count2 + 1
        Temp1$ = Program$(Count2)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 11)) = "SELECT CASE" THEN
            Nested = Nested + 1
        END IF
        IF UCASE$(LEFT$(Temp1$, 12)) <> "END SELECTIF" THEN
            IF UCASE$(LEFT$(Temp1$, 10)) = "END SELECT" THEN
                Nested = Nested - 1
            END IF
        END IF
        IF Nested = False THEN
            ProgramLine = Count2
            RETURN
        END IF
    LOOP
    ERROR 102
    RETURN

    ImbeddedifSelect:
    Imbedded = False
    Temp1$ = Program$(Count1)
    Temp1$ = STRIM$(Temp1$)
    IF UCASE$(LEFT$(Temp1$, 13)) <> "SELECTIF CASE" THEN
        RETURN
    END IF
    Imbedded = True
    Nested = 1
    Count2 = Count1
    DO WHILE Count2 < LastLine
        Count2 = Count2 + 1
        Temp1$ = Program$(Count2)
        Temp1$ = STRIM$(Temp1$)
        IF UCASE$(LEFT$(Temp1$, 13)) = "SELECTIF CASE" THEN
            Nested = Nested + 1
        END IF
        IF UCASE$(LEFT$(Temp1$, 12)) = "END SELECTIF" THEN
            Nested = Nested - 1
        END IF
        IF Nested = False THEN
            ProgramLine = Count2
            RETURN
        END IF
    LOOP
    ERROR 105
    RETURN
END SUB

SUB AssignKeyword
    Temp1$ = UCASE$(MID$(Out2, 4))
    Temp1$ = STRIM$(Temp1$)
    Out2 = MID$(Out2, 4)
    Out2 = STRIM$(Out2)
    IF LEFT$(Temp1$, 3) = "MID" THEN
        CALL AssignMidString
        EXIT SUB
    END IF
    IF LEFT$(Temp1$, 4) = "LEFT" THEN
        CALL AssignLeftString
        EXIT SUB
    END IF
    IF LEFT$(Temp1$, 5) = "RIGHT" THEN
        CALL AssignRightString
        EXIT SUB
    END IF
    CALL Assignment
END SUB

SUB Assignment
    Assign = False
    Temp1$ = UCASE$(LEFT$(Out2, 1))
    IF Temp1$ = "?" THEN
        Temp1$ = LTRIM$(MID$(Out2, 2))
        Temp2$ = LEFT$(Temp1$, 1)
        IF Temp2$ = "=" THEN
            Temp1$ = LTRIM$(MID$(Temp1$, 2))
            Out2 = Temp1$
            CALL Equate(Temp4#)
            Assign = True
            EXIT SUB
        END IF
    END IF
    IF Temp1$ >= "A" AND Temp1$ <= "Z" THEN
        Variable = ASC(Temp1$) - 64
        Temp1$ = LTRIM$(MID$(Out2, 2))
        Temp2$ = UCASE$(LEFT$(Temp1$, 1))
        IF Temp2$ >= "A" AND Temp2$ <= "Z" THEN
            Temp2$ = LTRIM$(MID$(Out2, 3))
            Var1$ = UCASE$(LEFT$(Temp2$, 1))
            IF Var1$ >= "A" AND Var1$ <= "Z" THEN
                Var1$ = MID$(Out2, 4)
                Var2$ = UCASE$(LEFT$(Var1$, 1))
                Var2$ = STRIM$(Var2$)
                IF LEFT$(Var2$, 1) = "=" THEN
                    Var1$ = MID$(Var1$, 2)
                    Var1$ = STRIM$(Var1$)
                    Var2$ = UCASE$(LEFT$(Out2, 3))
                    CALL Assignment4(Var1$, Var2$)
                    IF Assign THEN
                        CALL AssignEnd
                        EXIT SUB
                    END IF
                END IF
            ELSE
                IF Var1$ = "=" THEN
                    Var1$ = MID$(Out2, INSTR(Out2, "=") + 1)
                    Var1$ = STRIM$(Var1$)
                    Var2$ = UCASE$(LEFT$(Out2, 2))
                    CALL Assignment3(Var1$, Var2$) ' registers
                    IF Assign THEN
                        CALL AssignEnd
                        EXIT SUB
                    END IF
                END IF
            END IF
        END IF
        Temp1$ = STRIM$(Temp1$)
        CALL Assignment1(Temp1$, Variable)
        IF Assign THEN
            CALL AssignEnd
            EXIT SUB
        END IF
        IF LEFT$(Temp1$, 1) = "$" THEN
            Temp1$ = MID$(Temp1$, 2)
            Temp1$ = STRIM$(Temp1$)
            IF LEFT$(Temp1$, 1) = "(" THEN
                Strng = "<bad string token>"
                ERROR 92
            END IF
            IF LEFT$(Temp1$, 1) = "[" THEN
                Strng = "<bad string token>"
                ERROR 92
            END IF
            IF LEFT$(Temp1$, 1) = "{" THEN
                Strng = "<bad string token>"
                ERROR 92
            END IF
            IF LEFT$(Temp1$, 1) = "=" THEN
                Out2 = MID$(Temp1$, 2)
                Out2 = STRIM$(Out2)
                TokenIndex = 1
                CALL GetToken
                CALL Parse1(Temp3#)
                IF LastToken = False THEN
                    Strngs$(Variable) = Out3
                    Assign = True
                    CALL AssignEnd
                    EXIT SUB
                END IF
            END IF
        END IF
        IF LEFT$(Temp1$, 1) = "(" THEN
            Out2 = MID$(Temp1$, 2)
            Out2 = STRIM$(Out2)
            LastToken = False
            TokenIndex = 1
            CALL GetToken
            CALL Parse1(Temp3#)
            IF LastToken = True THEN
                Element = CINT(Temp3#)
                Temp1$ = MID$(Out2, TokenIndex)
                Temp1$ = STRIM$(Temp1$)
                CALL Assignment2(Temp1$, Variable, Element)
                IF Assign THEN
                    CALL AssignEnd
                    EXIT SUB
                END IF
            END IF
        END IF
    END IF
END SUB

SUB AssignEnd
    IF LEN(Strng) THEN
        CALL Parse1(X#)
        Strng = "<extra token>"
        ERROR 92
    END IF
END SUB

SUB AssignMidString
    Out2 = MID$(Out2, 4)
    IF LEN(Out2) THEN
        Out2 = STRIM$(Out2)
        Out2 = MID$(Out2, 3)
        Temp1$ = UCASE$(LEFT$(Out2, 1))
        IF Temp1$ >= "A" AND Temp1$ <= "Z" THEN
            Variable = ASC(Temp1$) - 64
            IF MID$(Out2, 2, 1) = "$" THEN
                Out2 = MID$(Out2, 4)
                LastToken = False
                TokenIndex = 1
                CALL GetToken
                CALL Parse1(Temp3#)
                Start = CINT(Temp3#)
                IF Strng = "," THEN
                    CALL GetToken
                    CALL Parse1(Temp3#)
                    Length = CINT(Temp3#)
                    Out2 = MID$(Out2, TokenIndex)
                    Out2 = STRIM$(Out2)
                    IF LEFT$(Out2, 1) = "=" THEN
                        Out2 = MID$(Out2, 2)
                        Out2 = STRIM$(Out2)
                        TokenIndex = 1
                        CALL GetToken
                        CALL Parse1(Temp3#)
                        IF LastToken = False THEN
                            IF Length = LEN(Out3) THEN
                                IF Start > LEN(Strngs(Variable)) THEN
                                    Strngs(Variable) = Strngs(Variable) + SPACE$(Start - LEN(Strngs(Variable)) - 1) + Out3
                                ELSE
                                    MID$(Strngs(Variable), Start, Length) = Out3
                                END IF
                                CALL AssignEnd
                                EXIT SUB
                            END IF
                        END IF
                    END IF
                END IF
            END IF
        END IF
    END IF
    Strng = "<illegal MID$ function call>"
    ERROR 162
END SUB

SUB AssignLeftString
    Out2 = MID$(Out2, 5)
    IF LEN(Out2) THEN
        Out2 = STRIM$(Out2)
        Out2 = MID$(Out2, 3)
        Temp1$ = UCASE$(LEFT$(Out2, 1))
        IF Temp1$ >= "A" AND Temp1$ <= "Z" THEN
            Variable = ASC(Temp1$) - 64
            IF MID$(Out2, 2, 1) = "$" THEN
                Out2 = MID$(Out2, 4)
                LastToken = False
                TokenIndex = 1
                CALL GetToken
                CALL Parse1(Temp3#)
                Start = CINT(Temp3#)
                Out2 = MID$(Out2, TokenIndex)
                Out2 = STRIM$(Out2)
                IF LEFT$(Out2, 1) = "=" THEN
                    Out2 = MID$(Out2, 2)
                    Out2 = STRIM$(Out2)
                    TokenIndex = 1
                    CALL GetToken
                    CALL Parse1(Temp3#)
                    IF LastToken = False THEN
                        IF Start = LEN(Out3) THEN
                            IF Strngs(Variable) = Nul THEN
                                Strngs(Variable) = Out3
                                CALL AssignEnd
                                EXIT SUB
                            END IF
                            MID$(Strngs(Variable), 1, Start) = Out3
                            CALL AssignEnd
                            EXIT SUB
                        END IF
                    END IF
                END IF
            END IF
        END IF
    END IF
    Strng = "<illegal LEFT$ function call>"
    ERROR 163
END SUB

SUB AssignRightString
    Out2 = MID$(Out2, 6)
    IF LEN(Out2) THEN
        Out2 = STRIM$(Out2)
        Out2 = MID$(Out2, 3)
        Temp1$ = UCASE$(LEFT$(Out2, 1))
        IF Temp1$ >= "A" AND Temp1$ <= "Z" THEN
            Variable = ASC(Temp1$) - 64
            IF MID$(Out2, 2, 1) = "$" THEN
                Out2 = MID$(Out2, 4)
                LastToken = False
                TokenIndex = 1
                CALL GetToken
                CALL Parse1(Temp3#)
                Start = CINT(Temp3#)
                Out2 = MID$(Out2, TokenIndex)
                Out2 = STRIM$(Out2)
                IF LEFT$(Out2, 1) = "=" THEN
                    Out2 = MID$(Out2, 2)
                    Out2 = STRIM$(Out2)
                    TokenIndex = 1
                    CALL GetToken
                    CALL Parse1(Temp3#)
                    Length = LEN(Strngs$(Variable)) - Start + 1
                    IF LastToken = False THEN
                        IF Start = LEN(Out3) THEN
                            IF Strngs(Variable) = Nul THEN
                                Strngs(Variable) = Out3
                                CALL AssignEnd
                                EXIT SUB
                            END IF
                            MID$(Strngs(Variable), Length, Start) = Out3
                            CALL AssignEnd
                            EXIT SUB
                        END IF
                    END IF
                END IF
            END IF
        END IF
    END IF
    Strng = "<illegal RIGHT$ function call>"
    ERROR 164
END SUB

REM CIRCLE STEP <x1>,<y1>,<radius>,[<color>],[<start>],[<end>],[<aspect>]
SUB DrawCircleStep
    AllowExtra = True
    Xcoor1 = False
    Xcoor1Set = False
    Ycoor1 = False
    Ycoor1Set = False
    Radius = False
    RadiusSet = False
    ColorCode = False
    ColorSet = False
    StartCircle = False
    StartSet = False
    EndCircle = False
    EndSet = False
    Aspect = False
    AspectSet = False
    Out2 = MID$(Out2, 12)
    Out2 = STRIM$(Out2)
    LastToken = False
    Out3 = Nul
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    Xcoor1 = CINT(Temp3#)
    IF LastToken = 3 THEN
        Xcoor1Set = False
    ELSE
        Xcoor1Set = True
    END IF
    IF Strng = "," THEN
        LastToken = False
        Out3 = Nul
        CALL GetToken
        CALL Parse1(Temp3#)
        Ycoor1 = CINT(Temp3#)
        IF LastToken = 3 THEN
            Ycoor1Set = False
        ELSE
            Ycoor1Set = True
        END IF
        IF Strng = "," THEN
            LastToken = False
            Out3 = Nul
            CALL GetToken
            CALL Parse1(Temp3#)
            Radius = CINT(Temp3#)
            IF LastToken = 3 THEN
                RadiusSet = False
            ELSE
                RadiusSet = True
            END IF
            IF Strng = "," THEN
                LastToken = False
                Out3 = Nul
                CALL GetToken
                CALL Parse1(Temp3#)
                ColorCode = CINT(Temp3#)
                IF LastToken = 3 THEN
                    ColorSet = False
                ELSE
                    ColorSet = True
                END IF
                IF Strng = "," THEN
                    LastToken = False
                    Out3 = Nul
                    CALL GetToken
                    CALL Parse1(Temp3#)
                    StartCircle = CINT(Temp3#)
                    IF LastToken = 3 THEN
                        StartSet = False
                    ELSE
                        StartSet = True
                    END IF
                    IF Strng = "," THEN
                        LastToken = False
                        Out3 = Nul
                        CALL GetToken
                        CALL Parse1(Temp3#)
                        EndCircle = CINT(Temp3#)
                        IF LastToken = 3 THEN
                            EndSet = False
                        ELSE
                            EndSet = True
                        END IF
                        IF Strng = "," THEN
                            LastToken = False
                            Out3 = Nul
                            CALL GetToken
                            CALL Parse1(Temp3#)
                            Aspect = CINT(Temp3#)
                            IF LastToken = 3 THEN
                                AspectSet = False
                            ELSE
                                AspectSet = True
                            END IF
                            IF Strng <> Nul THEN
                                ERROR 39
                            END IF
                        END IF
                    END IF
                END IF
            END IF
            IF Xcoor1Set AND Ycoor1Set AND RadiusSet THEN
                IF StartSet AND EndSet THEN
                    IF ColorSet THEN
                        IF AspectSet THEN
                            CIRCLE STEP(Xcoor1, Ycoor1), Radius, ColorCode, StartCircle, EndCircle, Aspect%
                        ELSE
                            CIRCLE STEP(Xcoor1, Ycoor1), Radius, ColorCode, StartCircle, EndCircle
                        END IF
                    ELSE
                        IF AspectSet THEN
                            CIRCLE STEP(Xcoor1, Ycoor1), Radius, , StartCircle, EndCircle, Aspect
                        ELSE
                            CIRCLE STEP(Xcoor1, Ycoor1), Radius, , StartCircle, EndCircle
                        END IF
                    END IF
                ELSE
                    IF StartSet OR EndSet THEN
                        ERROR 39
                    ELSE
                        IF ColorSet THEN
                            IF AspectSet THEN
                                CIRCLE STEP(Xcoor1, Ycoor1), Radius, ColorCode, , , Aspect
                            ELSE
                                CIRCLE STEP(Xcoor1, Ycoor1), Radius, ColorCode
                            END IF
                        ELSE
                            IF AspectSet THEN
                                CIRCLE STEP(Xcoor1, Ycoor1), Radius, , , , Aspect
                            ELSE
                                CIRCLE STEP(Xcoor1, Ycoor1), Radius
                            END IF
                        END IF
                    END IF
                END IF
                EXIT SUB
            END IF
        END IF
    END IF
    ERROR 39
END SUB

REM CIRCLE <x1>,<y1>,<radius>,[<color>],[<start>],[<end>],[<aspect>]
SUB DrawCircle
    AllowExtra = True
    Xcoor1 = False
    Xcoor1Set = False
    Ycoor1 = False
    Ycoor1Set = False
    Radius = False
    RadiusSet = False
    ColorCode = False
    ColorSet = False
    StartCircle = False
    StartSet = False
    EndCircle = False
    EndSet = False
    Aspect = False
    AspectSet = False
    Out2 = MID$(Out2, 7)
    Out2 = STRIM$(Out2)
    LastToken = False
    Out3 = Nul
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    Xcoor1 = CINT(Temp3#)
    IF LastToken = 3 THEN
        Xcoor1Set = False
    ELSE
        Xcoor1Set = True
    END IF
    IF Strng = "," THEN
        LastToken = False
        Out3 = Nul
        CALL GetToken
        CALL Parse1(Temp3#)
        Ycoor1 = CINT(Temp3#)
        IF LastToken = 3 THEN
            Ycoor1Set = False
        ELSE
            Ycoor1Set = True
        END IF
        IF Strng = "," THEN
            LastToken = False
            Out3 = Nul
            CALL GetToken
            CALL Parse1(Temp3#)
            Radius = CINT(Temp3#)
            IF LastToken = 3 THEN
                RadiusSet = False
            ELSE
                RadiusSet = True
            END IF
            IF Strng = "," THEN
                LastToken = False
                Out3 = Nul
                CALL GetToken
                CALL Parse1(Temp3#)
                ColorCode = CINT(Temp3#)
                IF LastToken = 3 THEN
                    ColorSet = False
                ELSE
                    ColorSet = True
                END IF
                IF Strng = "," THEN
                    LastToken = False
                    Out3 = Nul
                    CALL GetToken
                    CALL Parse1(Temp3#)
                    StartCircle = CINT(Temp3#)
                    IF LastToken = 3 THEN
                        StartSet = False
                    ELSE
                        StartSet = True
                    END IF
                    IF Strng = "," THEN
                        LastToken = False
                        Out3 = Nul
                        CALL GetToken
                        CALL Parse1(Temp3#)
                        EndCircle = CINT(Temp3#)
                        IF LastToken = 3 THEN
                            EndSet = False
                        ELSE
                            EndSet = True
                        END IF
                        IF Strng = "," THEN
                            LastToken = False
                            Out3 = Nul
                            CALL GetToken
                            CALL Parse1(Temp3#)
                            Aspect = CINT(Temp3#)
                            IF LastToken = 3 THEN
                                AspectSet = False
                            ELSE
                                AspectSet = True
                            END IF
                            IF Strng <> Nul THEN
                                ERROR 39
                            END IF
                        END IF
                    END IF
                END IF
            END IF
            IF Xcoor1Set AND Ycoor1Set AND RadiusSet THEN
                IF StartSet AND EndSet THEN
                    IF ColorSet THEN
                        IF AspectSet THEN
                            CIRCLE (Xcoor1, Ycoor1), Radius, ColorCode, StartCircle, EndCircle, Aspect%
                        ELSE
                            CIRCLE (Xcoor1, Ycoor1), Radius, ColorCode, StartCircle, EndCircle
                        END IF
                    ELSE
                        IF AspectSet THEN
                            CIRCLE (Xcoor1, Ycoor1), Radius, , StartCircle, EndCircle, Aspect
                        ELSE
                            CIRCLE (Xcoor1, Ycoor1), Radius, , StartCircle, EndCircle
                        END IF
                    END IF
                ELSE
                    IF StartSet OR EndSet THEN
                        ERROR 39
                    ELSE
                        IF ColorSet THEN
                            IF AspectSet THEN
                                CIRCLE (Xcoor1, Ycoor1), Radius, ColorCode, , , Aspect
                            ELSE
                                CIRCLE (Xcoor1, Ycoor1), Radius, ColorCode
                            END IF
                        ELSE
                            IF AspectSet THEN
                                CIRCLE (Xcoor1, Ycoor1), Radius, , , , Aspect
                            ELSE
                                CIRCLE (Xcoor1, Ycoor1), Radius
                            END IF
                        END IF
                    END IF
                END IF
                EXIT SUB
            END IF
        END IF
    END IF
    ERROR 39
END SUB

REM LINE STEP <x1>,<y1>, [STEP] <x2>,<y2>,[<color>],[<box>],[<style>]
SUB DrawLineStep
    AllowExtra = True
    Xcoor1 = False
    Xcoor1Set = False
    Ycoor1 = False
    Ycoor1Set = False
    Xcoor2 = False
    Xcoor2Set = False
    Ycoor2 = False
    Ycoor2Set = False
    ColorCode = False
    ColorSet = False
    BoxSet = False
    FilledSet = False
    Style = False
    StyleSet = False
    StepSet = False
    Out2 = MID$(Out2, 10)
    Out2 = XTRIM$(Out2, False)
    Out2 = UCASE$(Out2)
    LastToken = False
    Out3 = Nul
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    Xcoor1 = CINT(Temp3#)
    IF LastToken = 3 THEN
        Xcoor1Set = False
    ELSE
        Xcoor1Set = True
    END IF
    IF Strng = "," THEN
        LastToken = False
        Out3 = Nul
        CALL GetToken
        CALL Parse1(Temp3#)
        Ycoor1 = CINT(Temp3#)
        IF LastToken = 3 THEN
            Ycoor1Set = False
        ELSE
            Ycoor1Set = True
        END IF
        IF Strng = "," THEN
            Temp1$ = MID$(Out2, TokenIndex)
            IF LEFT$(Temp1$, 4) = "STEP" THEN
                StepSet = True
                TokenIndex = TokenIndex + 4
            END IF
            LastToken = False
            Out3 = Nul
            CALL GetToken
            CALL Parse1(Temp3#)
            Xcoor2 = CINT(Temp3#)
            IF LastToken = 3 THEN
                Xcoor2Set = False
            ELSE
                Xcoor2Set = True
            END IF
            IF Strng = "," THEN
                LastToken = False
                Out3 = Nul
                CALL GetToken
                CALL Parse1(Temp3#)
                Ycoor2 = CINT(Temp3#)
                IF LastToken = 3 THEN
                    Ycoor2Set = False
                ELSE
                    Ycoor2Set = True
                END IF
                IF Strng = "," THEN
                    LastToken = False
                    Out3 = Nul
                    CALL GetToken
                    CALL Parse1(Temp3#)
                    ColorCode = CINT(Temp3#)
                    IF LastToken = 3 THEN
                        ColorSet = False
                    ELSE
                        ColorSet = True
                    END IF
                    IF Strng = "," THEN
                        IF MID$(Out2, TokenIndex, 1) = "," THEN
                            CALL GetToken
                            CALL Parse1(Temp3#)
                        ELSE
                            LastToken = False
                            Out3 = Nul
                            CALL GetToken
                            CALL Parse1(Temp3#)
                            IF LastToken = 3 THEN
                                ERROR 28
                            END IF
                            SELECT CASE Out3
                                CASE "FB"
                                    BoxSet = True
                                    FilledSet = True
                                CASE "B"
                                    BoxSet = True
                                CASE ELSE
                                    ERROR 28
                            END SELECT
                        END IF
                        IF Strng = "," THEN
                            LastToken = False
                            Out3 = Nul
                            CALL GetToken
                            IF TokenIndex < LEN(Out2) THEN
                                CALL Parse1(Temp3#)
                                IF LastToken = 0 THEN
                                    ERROR 28
                                END IF
                                Style = CINT(Temp3#)
                                StyleSet = True
                                IF Strng <> Nul THEN
                                    ERROR 28
                                END IF
                            END IF
                        END IF
                    END IF
                END IF
            END IF
        END IF
        IF Xcoor1Set = False OR Ycoor1Set = False THEN
            ERROR 28
        END IF
        IF Xcoor2Set = False OR Ycoor2Set = False THEN
            ERROR 28
        END IF
        IF StepSet = False THEN
            IF BoxSet AND FilledSet THEN
                IF ColorSet AND StyleSet THEN
                    LINE STEP(Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), ColorCode, BF , Style
                ELSE
                    IF ColorSet THEN
                        LINE STEP(Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), ColorCode, BF
                    ELSE
                        IF StyleSet THEN
                            LINE STEP(Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), , BF , Style
                        ELSE
                            LINE STEP(Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), , BF
                        END IF
                    END IF
                END IF
            ELSE
                IF BoxSet THEN
                    IF ColorSet AND StyleSet THEN
                        LINE STEP(Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), ColorCode, B , Style
                    ELSE
                        IF ColorSet THEN
                            LINE STEP(Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), ColorCode, B
                        ELSE
                            IF StyleSet THEN
                                LINE STEP(Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), , B , Style
                            ELSE
                                LINE STEP(Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), , B
                            END IF
                        END IF
                    END IF
                ELSE
                    IF ColorSet AND StyleSet THEN
                        LINE STEP(Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), ColorCode, , Style
                    ELSE
                        IF ColorSet THEN
                            LINE STEP(Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), ColorCode
                        ELSE
                            IF StyleSet THEN
                                LINE STEP(Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), , , Style
                            ELSE
                                LINE STEP(Xcoor1, Ycoor1)-(Xcoor2, Ycoor2)
                            END IF
                        END IF
                    END IF
                END IF
            END IF
        ELSE
            IF BoxSet AND FilledSet THEN
                IF ColorSet AND StyleSet THEN
                    LINE STEP(Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2), ColorCode, BF , Style
                ELSE
                    IF ColorSet THEN
                        LINE STEP(Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2), ColorCode, BF
                    ELSE
                        IF StyleSet THEN
                            LINE STEP(Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2), , BF , Style
                        ELSE
                            LINE STEP(Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2), , BF
                        END IF
                    END IF
                END IF
            ELSE
                IF BoxSet THEN
                    IF ColorSet AND StyleSet THEN
                        LINE STEP(Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2), ColorCode, B , Style
                    ELSE
                        IF ColorSet THEN
                            LINE STEP(Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2), ColorCode, B
                        ELSE
                            IF StyleSet THEN
                                LINE STEP(Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2), , B , Style
                            ELSE
                                LINE STEP(Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2), , B
                            END IF
                        END IF
                    END IF
                ELSE
                    IF ColorSet AND StyleSet THEN
                        LINE STEP(Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2), ColorCode, , Style
                    ELSE
                        IF ColorSet THEN
                            LINE STEP(Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2), ColorCode
                        ELSE
                            IF StyleSet THEN
                                LINE STEP(Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2), , , Style
                            ELSE
                                LINE STEP(Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2)
                            END IF
                        END IF
                    END IF
                END IF
            END IF
        END IF
        EXIT SUB
    END IF
    ERROR 28
END SUB

REM LINE <x1>,<y1>, [STEP] <x2>,<y2>,[<color>],[<box>],[<style>]
SUB DrawLine
    AllowExtra = True
    Xcoor1 = False
    Xcoor1Set = False
    Ycoor1 = False
    Ycoor1Set = False
    Xcoor2 = False
    Xcoor2Set = False
    Ycoor2 = False
    Ycoor2Set = False
    ColorCode = False
    ColorSet = False
    BoxSet = False
    FilledSet = False
    Style = False
    StyleSet = False
    StepSet = False
    Out2 = MID$(Out2, 5)
    Out2 = XTRIM$(Out2, False)
    Out2 = UCASE$(Out2)
    LastToken = False
    Out3 = Nul
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    Xcoor1 = CINT(Temp3#)
    IF LastToken = 3 THEN
        Xcoor1Set = False
    ELSE
        Xcoor1Set = True
    END IF
    IF Strng = "," THEN
        LastToken = False
        Out3 = Nul
        CALL GetToken
        CALL Parse1(Temp3#)
        Ycoor1 = CINT(Temp3#)
        IF LastToken = 3 THEN
            Ycoor1Set = False
        ELSE
            Ycoor1Set = True
        END IF
        IF Strng = "," THEN
            Temp1$ = MID$(Out2, TokenIndex)
            IF LEFT$(Temp1$, 4) = "STEP" THEN
                StepSet = True
                TokenIndex = TokenIndex + 4
            END IF
            LastToken = False
            Out3 = Nul
            CALL GetToken
            CALL Parse1(Temp3#)
            Xcoor2 = CINT(Temp3#)
            IF LastToken = 3 THEN
                Xcoor2Set = False
            ELSE
                Xcoor2Set = True
            END IF
            IF Strng = "," THEN
                LastToken = False
                Out3 = Nul
                CALL GetToken
                CALL Parse1(Temp3#)
                Ycoor2 = CINT(Temp3#)
                IF LastToken = 3 THEN
                    Ycoor2Set = False
                ELSE
                    Ycoor2Set = True
                END IF
                IF Strng = "," THEN
                    LastToken = False
                    Out3 = Nul
                    CALL GetToken
                    CALL Parse1(Temp3#)
                    ColorCode = CINT(Temp3#)
                    IF LastToken = 3 THEN
                        ColorSet = False
                    ELSE
                        ColorSet = True
                    END IF
                    IF Strng = "," THEN
                        IF MID$(Out2, TokenIndex, 1) = "," THEN
                            CALL GetToken
                            CALL Parse1(Temp3#)
                        ELSE
                            LastToken = False
                            Out3 = Nul
                            CALL GetToken
                            CALL Parse1(Temp3#)
                            IF LastToken = 3 THEN
                                ERROR 28
                            END IF
                            SELECT CASE Out3
                                CASE "FB"
                                    BoxSet = True
                                    FilledSet = True
                                CASE "B"
                                    BoxSet = True
                                CASE ELSE
                                    ERROR 28
                            END SELECT
                        END IF
                        IF Strng = "," THEN
                            LastToken = False
                            Out3 = Nul
                            CALL GetToken
                            IF TokenIndex < LEN(Out2) THEN
                                CALL Parse1(Temp3#)
                                IF LastToken = 0 THEN
                                    ERROR 28
                                END IF
                                Style = CINT(Temp3#)
                                StyleSet = True
                                IF Strng <> Nul THEN
                                    ERROR 28
                                END IF
                            END IF
                        END IF
                    END IF
                END IF
            END IF
        END IF
        IF Xcoor2Set = False OR Ycoor2Set = False THEN
            ERROR 28
        END IF
        IF StepSet = False THEN
            IF Xcoor1Set AND Ycoor1Set THEN
                IF BoxSet AND FilledSet THEN
                    IF ColorSet AND StyleSet THEN
                        LINE (Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), ColorCode, BF , Style
                    ELSE
                        IF ColorSet THEN
                            LINE (Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), ColorCode, BF
                        ELSE
                            IF StyleSet THEN
                                LINE (Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), , BF , Style
                            ELSE
                                LINE (Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), , BF
                            END IF
                        END IF
                    END IF
                ELSE
                    IF BoxSet THEN
                        IF ColorSet AND StyleSet THEN
                            LINE (Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), ColorCode, B , Style
                        ELSE
                            IF ColorSet THEN
                                LINE (Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), ColorCode, B
                            ELSE
                                IF StyleSet THEN
                                    LINE (Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), , B , Style
                                ELSE
                                    LINE (Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), , B
                                END IF
                            END IF
                        END IF
                    ELSE
                        IF ColorSet AND StyleSet THEN
                            LINE (Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), ColorCode, , Style
                        ELSE
                            IF ColorSet THEN
                                LINE (Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), ColorCode
                            ELSE
                                IF StyleSet THEN
                                    LINE (Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), , , Style
                                ELSE
                                    LINE (Xcoor1, Ycoor1)-(Xcoor2, Ycoor2)
                                END IF
                            END IF
                        END IF
                    END IF
                END IF
            ELSE
                IF BoxSet AND FilledSet THEN
                    IF ColorSet AND StyleSet THEN
                        LINE -(Xcoor2, Ycoor2), ColorCode, BF , Style
                    ELSE
                        IF ColorSet THEN
                            LINE -(Xcoor2, Ycoor2), ColorCode, BF
                        ELSE
                            IF StyleSet THEN
                                LINE -(Xcoor2, Ycoor2), , BF , Style
                            ELSE
                                LINE -(Xcoor2, Ycoor2), , BF
                            END IF
                        END IF
                    END IF
                ELSE
                    IF BoxSet THEN
                        IF ColorSet AND StyleSet THEN
                            LINE -(Xcoor2, Ycoor2), ColorCode, B , Style
                        ELSE
                            IF ColorSet THEN
                                LINE -(Xcoor2, Ycoor2), ColorCode, B
                            ELSE
                                IF StyleSet THEN
                                    LINE -(Xcoor2, Ycoor2), , B , Style
                                ELSE
                                    LINE -(Xcoor2, Ycoor2), , B
                                END IF
                            END IF
                        END IF
                    ELSE
                        IF ColorSet AND StyleSet THEN
                            LINE -(Xcoor2, Ycoor2), ColorCode, , Style
                        ELSE
                            IF ColorSet THEN
                                LINE -(Xcoor2, Ycoor2), ColorCode
                            ELSE
                                IF StyleSet THEN
                                    LINE -(Xcoor2, Ycoor2), , , Style
                                ELSE
                                    LINE -(Xcoor2, Ycoor2)
                                END IF
                            END IF
                        END IF
                    END IF
                END IF
            END IF
        ELSE
            IF Xcoor1Set AND Ycoor1Set THEN
                IF BoxSet AND FilledSet THEN
                    IF ColorSet AND StyleSet THEN
                        LINE (Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2), ColorCode, BF , Style
                    ELSE
                        IF ColorSet THEN
                            LINE (Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2), ColorCode, BF
                        ELSE
                            IF StyleSet THEN
                                LINE (Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2), , BF , Style
                            ELSE
                                LINE (Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2), , BF
                            END IF
                        END IF
                    END IF
                ELSE
                    IF BoxSet THEN
                        IF ColorSet AND StyleSet THEN
                            LINE (Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2), ColorCode, B , Style
                        ELSE
                            IF ColorSet THEN
                                LINE (Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2), ColorCode, B
                            ELSE
                                IF StyleSet THEN
                                    LINE (Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2), , B , Style
                                ELSE
                                    LINE (Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2), , B
                                END IF
                            END IF
                        END IF
                    ELSE
                        IF ColorSet AND StyleSet THEN
                            LINE (Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2), ColorCode, , Style
                        ELSE
                            IF ColorSet THEN
                                LINE (Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2), ColorCode
                            ELSE
                                IF StyleSet THEN
                                    LINE (Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2), , , Style
                                ELSE
                                    LINE (Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2)
                                END IF
                            END IF
                        END IF
                    END IF
                END IF
            ELSE
                IF BoxSet AND FilledSet THEN
                    IF ColorSet AND StyleSet THEN
                        LINE -STEP(Xcoor2, Ycoor2), ColorCode, BF , Style
                    ELSE
                        IF ColorSet THEN
                            LINE -STEP(Xcoor2, Ycoor2), ColorCode, BF
                        ELSE
                            IF StyleSet THEN
                                LINE -STEP(Xcoor2, Ycoor2), , BF , Style
                            ELSE
                                LINE -STEP(Xcoor2, Ycoor2), , BF
                            END IF
                        END IF
                    END IF
                ELSE
                    IF BoxSet THEN
                        IF ColorSet AND StyleSet THEN
                            LINE -STEP(Xcoor2, Ycoor2), ColorCode, B , Style
                        ELSE
                            IF ColorSet THEN
                                LINE -STEP(Xcoor2, Ycoor2), ColorCode, B
                            ELSE
                                IF StyleSet THEN
                                    LINE -STEP(Xcoor2, Ycoor2), , B , Style
                                ELSE
                                    LINE -STEP(Xcoor2, Ycoor2), , B
                                END IF
                            END IF
                        END IF
                    ELSE
                        IF ColorSet AND StyleSet THEN
                            LINE -STEP(Xcoor2, Ycoor2), ColorCode, , Style
                        ELSE
                            IF ColorSet THEN
                                LINE -STEP(Xcoor2, Ycoor2), ColorCode
                            ELSE
                                IF StyleSet THEN
                                    LINE -STEP(Xcoor2, Ycoor2), , , Style
                                ELSE
                                    LINE -STEP(Xcoor2, Ycoor2)
                                END IF
                            END IF
                        END IF
                    END IF
                END IF
            END IF
        END IF
        EXIT SUB
    END IF
    ERROR 28
END SUB

REM TRIANGLE <x1>,<y1>,<x2>,<y2>,<x3>,<y3>,<color>
SUB DrawTriangle
    AllowExtra = True
    Xcoor1 = False
    Ycoor1 = False
    Xcoor2 = False
    Ycoor2 = False
    Xcoor3 = False
    Ycoor3 = False
    ColorCode = False
    Out2 = MID$(Out2, 9)
    Out2 = XTRIM$(Out2, False)
    Out2 = UCASE$(Out2)
    LastToken = False
    Out3 = Nul
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    Xcoor1 = CINT(Temp3#)
    IF LastToken = 3 THEN
        ERROR 168
    END IF
    IF Strng = "," THEN
        LastToken = False
        Out3 = Nul
        CALL GetToken
        CALL Parse1(Temp3#)
        Ycoor1 = CINT(Temp3#)
        IF LastToken = 3 THEN
            ERROR 168
        END IF
        IF Strng = "," THEN
            LastToken = False
            Out3 = Nul
            CALL GetToken
            CALL Parse1(Temp3#)
            Xcoor2 = CINT(Temp3#)
            IF LastToken = 3 THEN
                ERROR 168
            END IF
            IF Strng = "," THEN
                LastToken = False
                Out3 = Nul
                CALL GetToken
                CALL Parse1(Temp3#)
                Ycoor2 = CINT(Temp3#)
                IF LastToken = 3 THEN
                    ERROR 168
                END IF
                IF Strng = "," THEN
                    LastToken = False
                    Out3 = Nul
                    CALL GetToken
                    CALL Parse1(Temp3#)
                    Xcoor3 = CINT(Temp3#)
                    IF LastToken = 3 THEN
                        ERROR 168
                    END IF
                    IF Strng = "," THEN
                        LastToken = False
                        Out3 = Nul
                        CALL GetToken
                        CALL Parse1(Temp3#)
                        Ycoor3 = CINT(Temp3#)
                        IF LastToken = 3 THEN
                            ERROR 168
                        END IF
                        IF Strng = "," THEN
                            LastToken = False
                            Out3 = Nul
                            CALL GetToken
                            CALL Parse1(Temp3#)
                            ColorCode = CINT(Temp3#)
                            IF LastToken = 3 THEN
                                ERROR 168
                            END IF
                            IF Strng <> Nul THEN
                                ERROR 168
                            END IF
                            ' make triangle
                            LINE (Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), ColorCode
                            LINE (Xcoor2, Ycoor2)-(Xcoor3, Ycoor3), ColorCode
                            LINE (Xcoor3, Ycoor3)-(Xcoor1, Ycoor1), ColorCode
                            EXIT SUB
                        END IF
                    END IF
                END IF
            END IF
        END IF
    END IF
    ERROR 168
END SUB

REM DrawPolygon <x1>,<y1>,<r>,<n>,<a>,<c>
SUB DrawPolygon
    AllowExtra = True
    Out2 = MID$(Out2, 8)
    Out2 = XTRIM$(Out2, False)
    Out2 = UCASE$(Out2)
    LastToken = False
    Out3 = Nul
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    xc = CINT(Temp3#)
    IF LastToken = 3 THEN
        ERROR 169
    END IF
    IF Strng = "," THEN
        LastToken = False
        Out3 = Nul
        CALL GetToken
        CALL Parse1(Temp3#)
        yc = CINT(Temp3#)
        IF LastToken = 3 THEN
            ERROR 169
        END IF
        IF Strng = "," THEN
            LastToken = False
            Out3 = Nul
            CALL GetToken
            CALL Parse1(Temp3#)
            r = CINT(Temp3#)
            IF LastToken = 3 THEN
                ERROR 169
            END IF
            IF Strng = "," THEN
                LastToken = False
                Out3 = Nul
                CALL GetToken
                CALL Parse1(Temp3#)
                n = CINT(Temp3#)
                IF LastToken = 3 THEN
                    ERROR 169
                END IF
                IF Strng = "," THEN
                    LastToken = False
                    Out3 = Nul
                    CALL GetToken
                    CALL Parse1(Temp3#)
                    a = CINT(Temp3#)
                    IF LastToken = 3 THEN
                        ERROR 169
                    END IF
                    IF Strng = "," THEN
                        LastToken = False
                        Out3 = Nul
                        CALL GetToken
                        CALL Parse1(Temp3#)
                        c = CINT(Temp3#)
                        IF LastToken = 3 THEN
                            ERROR 169
                        END IF
                        IF Strng <> Nul THEN
                            ERROR 169
                        END IF
                        ' make polygon
                        IF n >= 3 AND n <= 30 THEN
                            x1 = xc + r * COS(PI2 * a)
                            y1 = yc + r * SIN(PI2 * a)
                            LINE (x1, y1)-(x1, y1), c
                            FOR i = 0 TO n
                                a = a + 180 / n
                                x1 = xc + r * COS(PI2 * a)
                                y1 = yc + r * SIN(PI2 * a)
                                LINE STEP(0, 0)-(x1, y1), c
                            NEXT
                            EXIT SUB
                        END IF
                    END IF
                END IF
            END IF
        END IF
    END IF
    ERROR 169
END SUB

SUB GetGraphics
    SELECT CASE ScreenMode
        CASE 1
            PlaneBits = 2
            Planes = 1
        CASE 2, 11
            PlaneBits = 1
            Planes = 1
        CASE 7, 8, 9, 12
            PlaneBits = 1
            Planes = 4
        CASE 10
            PlaneBits = 1
            Planes = 2
        CASE 13
            PlaneBits = 8
            Planes = 1
        CASE ELSE
            ERROR 49
    END SELECT
    Xcoor1 = False
    Ycoor1 = False
    Xcoor2 = False
    Ycoor2 = False
    Out2 = MID$(Out2, 4)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    Xcoor1 = CINT(Temp3#)
    IF Strng = "," THEN
        CALL GetToken
        CALL Parse1(Temp3#)
        Ycoor1 = CINT(Temp3#)
        IF Strng = "," THEN
            Temp1$ = UCASE$(MID$(Out2, TokenIndex))
            IF LEFT$(Temp1$, 4) = "STEP" THEN
                StepSet = True
                TokenIndex = TokenIndex + 4
            END IF
            CALL GetToken
            CALL Parse1(Temp3#)
            Xcoor2 = CINT(Temp3#)
            IF Strng = "," THEN
                CALL GetToken
                CALL Parse1(Temp3#)
                Ycoor2 = CINT(Temp3#)
                ArraySize = 4 + INT(((Xcoor2 - Xcoor1 + 1) * (PlaneBits) + 7) / 8) * Planes * ((Ycoor2 - Ycoor1) + 1)
                Elements = INT((ArraySize + 1) / 2)
                REDIM GraphicsScreen(1 TO Elements) AS INTEGER
                IF StepSet THEN
                    GET (Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2), GraphicsScreen()
                ELSE
                    GET (Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), GraphicsScreen()
                END IF
                EXIT SUB
            END IF
        END IF
    END IF
    ERROR 49
END SUB

SUB GetGraphicsStep
    SELECT CASE ScreenMode
        CASE 1
            PlaneBits = 2
            Planes = 1
        CASE 2, 11
            PlaneBits = 1
            Planes = 1
        CASE 7, 8, 9, 12
            PlaneBits = 1
            Planes = 4
        CASE 10
            PlaneBits = 1
            Planes = 2
        CASE 13
            PlaneBits = 8
            Planes = 1
        CASE ELSE
            ERROR 49
    END SELECT
    Xcoor1 = False
    Ycoor1 = False
    Xcoor2 = False
    Ycoor2 = False
    Out2 = MID$(Out2, 9)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    Xcoor1 = CINT(Temp3#)
    IF Strng = "," THEN
        CALL GetToken
        CALL Parse1(Temp3#)
        Ycoor1 = CINT(Temp3#)
        IF Strng = "," THEN
            Temp1$ = UCASE$(MID$(Out2, TokenIndex))
            IF LEFT$(Temp1$, 4) = "STEP" THEN
                StepSet = True
                TokenIndex = TokenIndex + 4
            END IF
            CALL GetToken
            CALL Parse1(Temp3#)
            Xcoor2 = CINT(Temp3#)
            IF Strng = "," THEN
                CALL GetToken
                CALL Parse1(Temp3#)
                Ycoor2 = CINT(Temp3#)
                ArraySize = 4 + INT(((Xcoor2 - Xcoor1 + 1) * (PlaneBits) + 7) / 8) * Planes * ((Ycoor2 - Ycoor1) + 1)
                Elements = INT((ArraySize + 1) / 2)
                REDIM GraphicsScreen(1 TO Elements) AS INTEGER
                IF StepSet THEN
                    GET STEP(Xcoor1, Ycoor1)-STEP(Xcoor2, Ycoor2), GraphicsScreen()
                ELSE
                    GET STEP(Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), GraphicsScreen()
                END IF
                EXIT SUB
            END IF
        END IF
    END IF
    ERROR 49
END SUB

SUB PutGraphics
    Xcoor1 = False
    Ycoor1 = False
    Out2 = MID$(Out2, 4)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    Xcoor1 = CINT(Temp3#)
    IF Strng = "," THEN
        CALL GetToken
        CALL Parse1(Temp3#)
        Ycoor1 = CINT(Temp3#)
        IF Strng = "," THEN
            Temp1$ = MID$(Out2, TokenIndex)
            Temp1$ = STRIM$(Temp1$)
            Temp1$ = UCASE$(Temp1$)
            IF LEFT$(Temp1$, 4) = "PSET" THEN
                PUT (Xcoor1, Ycoor1), GraphicsScreen(), PSET
                EXIT SUB
            ELSE
                IF LEFT$(Temp1$, 6) = "PRESET" THEN
                    PUT (Xcoor1, Ycoor1), GraphicsScreen(), PRESET
                    EXIT SUB
                ELSE
                    IF LEFT$(Temp1$, 3) = "AND" THEN
                        PUT (Xcoor1, Ycoor1), GraphicsScreen(), AND
                        EXIT SUB
                    ELSE
                        IF LEFT$(Temp1$, 2) = "OR" THEN
                            PUT (Xcoor1, Ycoor1), GraphicsScreen(), OR
                            EXIT SUB
                        ELSE
                            IF LEFT$(Temp1$, 3) = "XOR" THEN
                                PUT (Xcoor1, Ycoor1), GraphicsScreen(), XOR
                                EXIT SUB
                            END IF
                        END IF
                    END IF
                END IF
            END IF
        ELSE
            PUT (Xcoor1, Ycoor1), GraphicsScreen()
            EXIT SUB
        END IF
    END IF
    ERROR 49
END SUB

SUB PutGraphicsStep
    Xcoor1 = False
    Ycoor1 = False
    Out2 = MID$(Out2, 9)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    Xcoor1 = CINT(Temp3#)
    IF Strng = "," THEN
        CALL GetToken
        CALL Parse1(Temp3#)
        Ycoor1 = CINT(Temp3#)
        IF Strng = "," THEN
            Temp1$ = MID$(Out2, TokenIndex)
            Temp1$ = STRIM$(Temp1$)
            Temp1$ = UCASE$(Temp1$)
            IF LEFT$(Temp1$, 4) = "PSET" THEN
                PUT STEP(Xcoor1, Ycoor1), GraphicsScreen(), PSET
                EXIT SUB
            ELSE
                IF LEFT$(Temp1$, 6) = "PRESET" THEN
                    PUT STEP(Xcoor1, Ycoor1), GraphicsScreen(), PRESET
                    EXIT SUB
                ELSE
                    IF LEFT$(Temp1$, 3) = "AND" THEN
                        PUT STEP(Xcoor1, Ycoor1), GraphicsScreen(), AND
                        EXIT SUB
                    ELSE
                        IF LEFT$(Temp1$, 2) = "OR" THEN
                            PUT STEP(Xcoor1, Ycoor1), GraphicsScreen(), OR
                            EXIT SUB
                        ELSE
                            IF LEFT$(Temp1$, 3) = "XOR" THEN
                                PUT STEP(Xcoor1, Ycoor1), GraphicsScreen(), XOR
                                EXIT SUB
                            END IF
                        END IF
                    END IF
                END IF
            END IF
        ELSE
            PUT STEP(Xcoor1, Ycoor1), GraphicsScreen()
            EXIT SUB
        END IF
    END IF
    ERROR 49
END SUB

SUB WindowScreen (Var)
    IF Var = 1 THEN
        WindowType = True
        Out2 = MID$(Out2, 14)
        Out2 = STRIM$(Out2)
    ELSE
        WindowType = False
        Out2 = MID$(Out2, 7)
        Out2 = STRIM$(Out2)
    END IF
    Xcoor1 = False
    Xcoor2 = False
    Ycoor1 = False
    Ycoor2 = False
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    Xcoor1 = CINT(Temp3#)
    IF Strng = "," THEN
        CALL GetToken
        CALL Parse1(Temp3#)
        Ycoor1 = CINT(Temp3#)
        IF Strng = "," THEN
            CALL GetToken
            CALL Parse1(Temp3#)
            Xcoor2 = CINT(Temp3#)
            IF Strng = "," THEN
                CALL GetToken
                CALL Parse1(Temp3#)
                Ycoor2 = CINT(Temp3#)
                IF WindowType THEN
                    WINDOW SCREEN(Xcoor1, Ycoor1)-(Xcoor2, Ycoor2)
                ELSE
                    WINDOW (Xcoor1, Ycoor1)-(Xcoor2, Ycoor2)
                END IF
                EXIT SUB
            END IF
        END IF
    END IF
    ERROR 78
END SUB

SUB ViewScreen (Var)
    AllowExtra = True
    IF Var = 1 THEN
        ViewType = True
        Out2 = MID$(Out2, 12)
        Out2 = STRIM$(Out2)
    ELSE
        ViewType = False
        Out2 = MID$(Out2, 5)
        Out2 = STRIM$(Out2)
    END IF
    Xcoor1 = False
    Xcoor2 = False
    Ycoor1 = False
    Ycoor2 = False
    ColorCode = False
    ColorSet = False
    BorderColor = False
    BorderSet = False
    LastToken = False
    Out3 = Nul
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    Xcoor1 = CINT(Temp3#)
    IF Strng = "," THEN
        LastToken = False
        Out3 = Nul
        CALL GetToken
        CALL Parse1(Temp3#)
        Ycoor1 = CINT(Temp3#)
        IF Strng = "," THEN
            LastToken = False
            Out3 = Nul
            CALL GetToken
            CALL Parse1(Temp3#)
            Xcoor2 = CINT(Temp3#)
            IF Strng = "," THEN
                LastToken = False
                Out3 = Nul
                CALL GetToken
                CALL Parse1(Temp3#)
                Ycoor2 = CINT(Temp3#)
                IF Strng = "," THEN
                    LastToken = False
                    Out3 = Nul
                    CALL GetToken
                    CALL Parse1(Temp3#)
                    ColorCode = CINT(Temp3#)
                    IF LastToken THEN
                        ColorSet = True
                    END IF
                    IF Strng = "," THEN
                        LastToken = False
                        Out3 = Nul
                        CALL GetToken
                        CALL Parse1(Temp3#)
                        BorderColor = CINT(Temp3#)
                        IF LastToken THEN
                            BorderSet = True
                        END IF
                    END IF
                END IF
                IF ViewType THEN
                    IF ColorSet AND BorderSet THEN
                        VIEW SCREEN(Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), ColorCode, BorderColor
                    ELSE
                        IF ColorSet THEN
                            VIEW SCREEN(Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), ColorCode, BorderColor
                        ELSE
                            IF BorderSet THEN
                                VIEW SCREEN(Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), , BorderColor
                            ELSE
                                VIEW SCREEN(Xcoor1, Ycoor1)-(Xcoor2, Ycoor2)
                            END IF
                        END IF
                    END IF
                ELSE
                    IF ColorSet AND BorderSet THEN
                        VIEW (Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), ColorCode, BorderColor
                    ELSE
                        IF ColorSet THEN
                            VIEW (Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), ColorCode
                        ELSE
                            IF BorderSet THEN
                                VIEW (Xcoor1, Ycoor1)-(Xcoor2, Ycoor2), , BorderColor
                            ELSE
                                VIEW (Xcoor1, Ycoor1)-(Xcoor2, Ycoor2)
                            END IF
                        END IF
                    END IF
                END IF
                EXIT SUB
            END IF
        END IF
    END IF
    ERROR 77
END SUB

SUB PaintArea
    AllowExtra = True
    Xcoor1 = False
    Xcoor1Set = False
    Ycoor1 = False
    Ycoor1Set = False
    PaintType = False
    PaintStyle$ = Nul
    BorderColor = False
    BorderSet = False
    BackGroundStyle$ = Nul
    Out2 = MID$(Out2, 6)
    Out2 = STRIM$(Out2)
    LastToken = False
    Out3 = Nul
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    Xcoor1 = CINT(Temp3#)
    IF LastToken THEN
        Xcoor1Set = True
    END IF
    IF Strng = "," THEN
        LastToken = False
        Out3 = Nul
        CALL GetToken
        CALL Parse1(Temp3#)
        Ycoor1 = CINT(Temp3#)
        IF LastToken THEN
            Ycoor1Set = True
        END IF
        IF Strng = "," THEN
            LastToken = False
            Out3 = Nul
            CALL GetToken
            CALL Parse1(Temp3#)
            IF LastToken = False THEN
                PaintType = True
                PaintStyle$ = Out3
            ELSE
                PaintType = CINT(Temp3#)
            END IF
            IF Strng = "," THEN
                LastToken = False
                Out3 = Nul
                CALL GetToken
                CALL Parse1(Temp3#)
                BorderColor = CINT(Temp3#)
                IF LastToken THEN
                    BorderSet = True
                END IF
                IF Strng = "," THEN
                    LastToken = False
                    Out3 = Nul
                    CALL GetToken
                    CALL Parse1(Temp3#)
                    BackGroundStyle$ = Out3
                END IF
            END IF
        END IF
        IF Xcoor1Set AND Ycoor1Set THEN
            IF PaintType = True THEN
                IF BorderSet THEN
                    IF LEN(BackGroundStyle$) THEN
                        PAINT (Xcoor1, Ycoor1), PaintStyle$, BorderColor, BackGroundStyle$
                    ELSE
                        PAINT (Xcoor1, Ycoor1), PaintStyle$, BorderColor
                    END IF
                ELSE
                    IF LEN(BackGroundStyle$) THEN
                        PAINT (Xcoor1, Ycoor1), PaintStyle$, , BackGroundStyle$
                    ELSE
                        PAINT (Xcoor1, Ycoor1), PaintStyle$
                    END IF
                END IF
            ELSE
                IF PaintType > False THEN
                    IF BorderSet THEN
                        IF LEN(BackGroundStyle$) THEN
                            ERROR 48
                            EXIT SUB
                        ELSE
                            PAINT (Xcoor1, Ycoor1), PaintType, BorderColor
                        END IF
                    ELSE
                        IF LEN(BackGroundStyle$) THEN
                            ERROR 48
                            EXIT SUB
                        ELSE
                            PAINT (Xcoor1, Ycoor1), PaintType
                        END IF
                    END IF
                ELSE
                    IF BorderSet THEN
                        IF LEN(BackGroundStyle$) THEN
                            ERROR 48
                            EXIT SUB
                        ELSE
                            PAINT (Xcoor1, Ycoor1), , BorderColor
                        END IF
                    ELSE
                        IF LEN(BackGroundStyle$) THEN
                            ERROR 48
                            EXIT SUB
                        ELSE
                            PAINT (Xcoor1, Ycoor1)
                        END IF
                    END IF
                END IF
            END IF
            EXIT SUB
        END IF
    END IF
    ERROR 48
END SUB

SUB PaintAreaStep
    AllowExtra = True
    Xcoor1 = False
    Xcoor1Set = False
    Ycoor1 = False
    Ycoor1Set = False
    PaintType = False
    PaintStyle$ = Nul
    BorderColor = False
    BorderSet = False
    BackGroundStyle$ = Nul
    Out2 = MID$(Out2, 11)
    Out2 = STRIM$(Out2)
    LastToken = False
    Out3 = Nul
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    Xcoor1 = CINT(Temp3#)
    IF LastToken THEN
        Xcoor1Set = True
    END IF
    IF Strng = "," THEN
        LastToken = False
        Out3 = Nul
        CALL GetToken
        CALL Parse1(Temp3#)
        Ycoor1 = CINT(Temp3#)
        IF LastToken THEN
            Ycoor1Set = True
        END IF
        IF Strng = "," THEN
            LastToken = False
            Out3 = Nul
            CALL GetToken
            CALL Parse1(Temp3#)
            IF LastToken = False THEN
                PaintType = True
                PaintStyle$ = Out3
            ELSE
                PaintType = CINT(Temp3#)
            END IF
            IF Strng = "," THEN
                LastToken = False
                Out3 = Nul
                CALL GetToken
                CALL Parse1(Temp3#)
                BorderColor = CINT(Temp3#)
                IF LastToken THEN
                    BorderSet = True
                END IF
                IF Strng = "," THEN
                    LastToken = False
                    Out3 = Nul
                    CALL GetToken
                    CALL Parse1(Temp3#)
                    BackGroundStyle$ = Out3
                END IF
            END IF
        END IF
        IF Xcoor1Set AND Ycoor1Set THEN
            IF PaintType = True THEN
                IF BorderSet THEN
                    IF LEN(BackGroundStyle$) THEN
                        PAINT STEP(Xcoor1, Ycoor1), PaintStyle$, BorderColor, BackGroundStyle$
                    ELSE
                        PAINT STEP(Xcoor1, Ycoor1), PaintStyle$, BorderColor
                    END IF
                ELSE
                    IF LEN(BackGroundStyle$) THEN
                        PAINT STEP(Xcoor1, Ycoor1), PaintStyle$, , BackGroundStyle$
                    ELSE
                        PAINT STEP(Xcoor1, Ycoor1), PaintStyle$
                    END IF
                END IF
            ELSE
                IF PaintType > False THEN
                    IF BorderSet THEN
                        IF LEN(BackGroundStyle$) THEN
                            ERROR 48
                            EXIT SUB
                        ELSE
                            PAINT STEP(Xcoor1, Ycoor1), PaintType, BorderColor
                        END IF
                    ELSE
                        IF LEN(BackGroundStyle$) THEN
                            ERROR 48
                            EXIT SUB
                        ELSE
                            PAINT STEP(Xcoor1, Ycoor1), PaintType
                        END IF
                    END IF
                ELSE
                    IF BorderSet THEN
                        IF LEN(BackGroundStyle$) THEN
                            ERROR 48
                            EXIT SUB
                        ELSE
                            PAINT STEP(Xcoor1, Ycoor1), , BorderColor
                        END IF
                    ELSE
                        IF LEN(BackGroundStyle$) THEN
                            ERROR 48
                            EXIT SUB
                        ELSE
                            PAINT STEP(Xcoor1, Ycoor1)
                        END IF
                    END IF
                END IF
            END IF
            EXIT SUB
        END IF
    END IF
    ERROR 48
END SUB

SUB PrintExpression
    AllowExtra = True
    Printing = True
    LastToken = False
    Out3 = Nul
    Out4 = Nul
    Temp# = False
    TokenIndex = 1

    IF RIGHT$(Out2, 1) = ";" OR RIGHT$(Out2, 1) = "," THEN
        LineFeed = True
        Out2 = Out2 + Quote + Quote + ";"
    ELSE
        LineFeed = False
        Out2 = Out2 + ";" + Quote + Quote
    END IF

    PrinterLF = 1
    Out2 = MID$(Out2, 6)
    Out2 = STRIM$(Out2)
    DO
        LastToken = False
        CALL GetToken
        CALL Parse1(Temp3#)
        IF ErrorValue THEN
            ErrorValue = 0
            EXIT SUB
        END IF
        SELECT CASE Strng
            CASE ","
                SELECT CASE LastToken
                    CASE -1
                        PRINT STR$(Temp3#), " ";
                    CASE 0
                        PRINT Out3, " ";
                    CASE ELSE
                        PRINT "",
                END SELECT
            CASE ";"
                SELECT CASE LastToken
                    CASE -1
                        PRINT STR$(Temp3#);
                    CASE 0
                        PRINT Out3;
                    CASE ELSE
                        PRINT "";
                END SELECT
            CASE ELSE
                IF LEN(Strng) THEN
                    Strng = "<extra token>"
                    ERROR 92
                END IF
                EXIT DO
        END SELECT
        IF TokenIndex > LEN(Out2) THEN
            EXIT DO
        END IF
    LOOP
    IF LineFeed = False THEN
        PRINT
    END IF
    PrinterLF = False
    Printing = False
END SUB

SUB PrintExpressionFile
    AllowExtra = True
    Out2 = MID$(Out2, 8)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    FileNum% = CINT(Temp3#)
    IF FileNum% <= 0 OR FileNum% > MaxFiles THEN
        ERROR 126
        EXIT SUB
    END IF
    IF Strng = "," THEN
        Out2 = MID$(Out2, TokenIndex)
        Out2 = STRIM$(Out2)
        LastToken = False
        Out3 = Nul
        Out4 = Nul
        Temp# = False
        TokenIndex = 1

        IF RIGHT$(Out2, 1) = ";" OR RIGHT$(Out2, 1) = "," THEN
            LineFeed = True
            Out2 = Out2 + Quote + Quote + ";"
        ELSE
            LineFeed = False
            Out2 = Out2 + ";" + Quote + Quote
        END IF

        DO
            LastToken = False
            CALL GetToken
            CALL Parse1(Temp3#)
            IF ErrorValue THEN
                ErrorValue = 0
                EXIT SUB
            END IF
            SELECT CASE Strng
                CASE ","
                    SELECT CASE LastToken
                        CASE -1
                            PRINT #FileNum%, STR$(Temp3#), " ";
                        CASE 0
                            PRINT #FileNum%, Out3, " ";
                        CASE ELSE
                            PRINT #FileNum%, "",
                    END SELECT
                CASE ";"
                    SELECT CASE LastToken
                        CASE -1
                            PRINT #FileNum%, STR$(Temp3#);
                        CASE 0
                            PRINT #FileNum%, Out3;
                        CASE ELSE
                            PRINT #FileNum%, "";
                    END SELECT
                CASE ELSE
                    IF LEN(Strng) THEN
                        Strng = "<extra token>"
                        ERROR 92
                    END IF
                    EXIT DO
            END SELECT
            IF TokenIndex > LEN(Out2) THEN
                EXIT DO
            END IF
        LOOP
        IF LineFeed = False THEN
            PRINT #FileNum%, CHR$(13); CHR$(10);
        END IF
        EXIT SUB
    END IF
    ERROR 32
END SUB

SUB LprintExpression
    AllowExtra = True
    Printing = True
    LastToken = False
    Out3 = Nul
    Out4 = Nul
    Temp# = False
    TokenIndex = 1

    IF RIGHT$(Out2, 1) = ";" OR RIGHT$(Out2, 1) = "," THEN
        LineFeed = True
        Out2 = Out2 + Quote + Quote + ";"
    ELSE
        LineFeed = False
        Out2 = Out2 + ";" + Quote + Quote
    END IF

    PrinterLF = True
    Out2 = MID$(Out2, 7)
    Out2 = STRIM$(Out2)
    DO
        LastToken = False
        CALL GetToken
        CALL Parse1(Temp3#)
        IF ErrorValue THEN
            ErrorValue = 0
            EXIT SUB
        END IF
        SELECT CASE Strng
            CASE ","
                SELECT CASE LastToken
                    CASE -1
                        LPRINT STR$(Temp3#),
                    CASE 0
                        LPRINT Out3,
                    CASE ELSE
                        LPRINT "",
                END SELECT
            CASE ";"
                SELECT CASE LastToken
                    CASE -1
                        LPRINT STR$(Temp3#);
                    CASE 0
                        LPRINT Out3;
                    CASE ELSE
                        LPRINT "";
                END SELECT
            CASE ELSE
                IF LEN(Strng) THEN
                    Strng = "<extra token>"
                    ERROR 92
                END IF
                EXIT DO
        END SELECT
        IF TokenIndex > LEN(Out2) THEN
            EXIT DO
        END IF
    LOOP
    IF LineFeed = False THEN
        LPRINT
    END IF
    PrinterLF = False
    Printing = False
END SUB

SUB SprintExpression
    AllowExtra = True
    Printing = True
    LastToken = False
    Out3 = Nul
    Out4 = Nul
    Temp# = False
    TokenIndex = 1

    IF RIGHT$(Out2, 1) = ";" OR RIGHT$(Out2, 1) = "," THEN
        LineFeed = True
        Out2 = Out2 + Quote + Quote + ";"
    ELSE
        LineFeed = False
        Out2 = Out2 + ";" + Quote + Quote
    END IF

    PrinterLF = 1
    Out2 = MID$(Out2, 7)
    Out2 = STRIM$(Out2)
    DO
        LastToken = False
        CALL GetToken
        CALL Parse1(Temp3#)
        IF ErrorValue THEN
            ErrorValue = 0
            EXIT SUB
        END IF
        SELECT CASE Strng
            CASE ","
                SELECT CASE LastToken
                    CASE -1
                        PRINT CHR$(Temp3#), " ";
                    CASE 0
                        PRINT Out3, " ";
                    CASE ELSE
                        PRINT "",
                END SELECT
            CASE ";"
                SELECT CASE LastToken
                    CASE -1
                        PRINT CHR$(Temp3#);
                    CASE 0
                        PRINT Out3;
                    CASE ELSE
                        PRINT "";
                END SELECT
            CASE ELSE
                IF LEN(Strng) THEN
                    Strng = "<extra token>"
                    ERROR 92
                END IF
                EXIT DO
        END SELECT
        IF TokenIndex > LEN(Out2) THEN
            EXIT DO
        END IF
    LOOP
    IF LineFeed = False THEN
        PRINT
    END IF
    PrinterLF = False
    Printing = False
END SUB

' special print function requires:
'    Uprint (<x>,"x"), (<x>,"x"), ...
SUB UprintExpression
    AllowExtra = True
    Printing = True
    LastToken = False
    Out3 = Nul
    Out4 = Nul
    Temp# = False
    TokenIndex = 1
    Out2 = XTRIM$(Out2, True)

    IF RIGHT$(Out2, 1) = ";" OR RIGHT$(Out2, 1) = "," THEN
        LineFeed = True
    ELSE
        LineFeed = False
    END IF

    PrinterLF = 1
    Out2 = MID$(Out2, 7)
    Out2 = STRIM$(Out2)
    DO
        LastToken = False
        CALL GetToken
        IF Strng <> "(" THEN
            Strng = "<missing left token>"
            ERROR 92
            EXIT SUB
        END IF
        CALL GetToken
        CALL Parse1(Temp3#)
        IF ErrorValue THEN
            ErrorValue = 0
            EXIT SUB
        END IF
        Number# = Temp3#
        CALL GetToken
        CALL Parse1(Temp3#)
        IF ErrorValue THEN
            ErrorValue = 0
            EXIT SUB
        END IF
        Strng = MID$(Out2, TokenIndex, 1)
        TokenIndex = TokenIndex + 1
        SELECT CASE Strng
            CASE ","
                SELECT CASE LastToken
                    CASE -1
                        Strng = "<string error>"
                        ERROR 92
                    CASE 0
                        PRINT USING Out3; Number#;
                        PRINT , " ";
                    CASE ELSE
                        PRINT "",
                END SELECT
            CASE ";"
                SELECT CASE LastToken
                    CASE -1
                        Strng = "<string error>"
                        ERROR 92
                    CASE 0
                        PRINT USING Out3; Number#;
                    CASE ELSE
                        PRINT "";
                END SELECT
            CASE ELSE
                IF LEN(Strng) THEN
                    Strng = "<extra token>"
                    ERROR 92
                END IF
                SELECT CASE LastToken
                    CASE -1
                        Strng = "<string error>"
                        ERROR 92
                    CASE 0
                        PRINT USING Out3; Number#;
                    CASE ELSE
                        PRINT "";
                END SELECT
                EXIT DO
        END SELECT
        IF TokenIndex > LEN(Out2) THEN
            EXIT DO
        END IF
    LOOP
    IF RIGHT$(Out2, 1) = ";" OR RIGHT$(Out2, 1) = "," THEN
        Out2 = LEFT$(Out2, LEN(Out2) - 1)
    END IF
    IF RIGHT$(Out2, 1) <> ")" THEN
        Strng = "<missing right token>"
        ERROR 92
        EXIT SUB
    END IF
    IF LineFeed = False THEN
        PRINT
    END IF
    PrinterLF = False
    Printing = False
END SUB

SUB LineInputExpression (Var)
    IF Var = 1 THEN
        AddCursor = False
        Temp1$ = MID$(Out2, 12)
    ELSE
        AddCursor = True
        Temp1$ = MID$(Out2, 11)
    END IF
    Temp1$ = STRIM$(Temp1$)
    TokenIndex = 1
    Out2 = Temp1$
    LastToken = True
    Quotes = False
    CALL GetToken
    CALL Parse1(Temp3#)
    IF LastToken = False THEN
        IF Quotes THEN
            PRINT Out3;
            Temp1$ = MID$(Out2, TokenIndex)
        END IF
    END IF
    Temp1$ = STRIM$(Temp1$)
    Temp1$ = UCASE$(Temp1$)
    SELECT CASE LEN(Temp1$)
        CASE 1
            IF Temp1$ >= "A" AND Temp1$ <= "Z" THEN
                Variable = ASC(Temp1$) - 64
                LOCATE , , Visible
                LINE INPUT ; Temp2$
                Variables(Variable) = VAL(Temp2$)
            END IF
        CASE 2
            IF MID$(Temp1$, 2, 1) = "$" THEN
                Temp1$ = LEFT$(Temp1$, 1)
                IF Temp1$ >= "A" AND Temp1$ <= "Z" THEN
                    Variable = ASC(Temp1$) - 64
                    LOCATE , , Visible
                    LINE INPUT ; Temp2$
                    Strngs$(Variable) = Temp2$
                END IF
            END IF
        CASE 3
            IF RIGHT$(Temp1$, 2) = "()" THEN
                Temp1$ = LEFT$(Temp1$, 1)
                IF Temp1$ >= "A" AND Temp1$ <= "Z" THEN
                    Variable = ASC(Temp1$) - 64
                    LOCATE , , Visible
                    LINE INPUT ; Temp2$
                    FOR Temp = 1 TO LEN(Temp2$)
                        Arrays(Variable, Temp) = ASC(MID$(Temp2$, Temp, 1))
                        IF Temp >= MaxArrays THEN
                            EXIT FOR
                        END IF
                    NEXT
                END IF
            END IF
        CASE ELSE
            Out2 = MID$(Temp1$, 2)
            Temp1$ = LEFT$(Temp1$, 1)
            IF Temp1$ >= "A" AND Temp1$ <= "Z" THEN
                Variable = ASC(Temp1$) - 64
                CALL Equate(Temp3#)
                Element = CINT(Temp3#)
                IF Element > False AND Element <= MaxArrays THEN
                    LOCATE , , Visible
                    LINE INPUT ; Temp2$
                    Arrays(Variable, Element) = VAL(Temp2$)
                ELSE
                    ERROR 9
                END IF
            END IF
    END SELECT
    IF AddCursor THEN
        PRINT
    END IF
END SUB

SUB LineInputExpFile
    Out2 = MID$(Out2, 13)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    FileNum% = CINT(Temp3#)
    IF FileNum% <= 0 OR FileNum% > MaxFiles THEN
        ERROR 126
        EXIT SUB
    END IF
    IF Strng = "," THEN
        Temp1$ = MID$(Out2, TokenIndex)
        Temp1$ = STRIM$(Temp1$)
        Temp1$ = UCASE$(Temp1$)
        SELECT CASE LEN(Temp1$)
            CASE 1
                IF Temp1$ >= "A" AND Temp1$ <= "Z" THEN
                    Variable = ASC(Temp1$) - 64
                    LINE INPUT #FileNum%, Temp2$
                    IF RIGHT$(Temp2$, 1) = CHR$(10) THEN
                        Temp2$ = LEFT$(Temp2$, LEN(Temp2$) - 1)
                    END IF
                    IF RIGHT$(Temp2$, 1) = CHR$(13) THEN
                        Temp2$ = LEFT$(Temp2$, LEN(Temp2$) - 1)
                    END IF
                    Variables(Variable) = VAL(Temp2$)
                END IF
            CASE 2
                IF MID$(Temp1$, 2, 1) = "$" THEN
                    Temp1$ = LEFT$(Temp1$, 1)
                    IF Temp1$ >= "A" AND Temp1$ <= "Z" THEN
                        Variable = ASC(Temp1$) - 64
                        LINE INPUT #FileNum%, Temp2$
                        IF RIGHT$(Temp2$, 1) = CHR$(10) THEN
                            Temp2$ = LEFT$(Temp2$, LEN(Temp2$) - 1)
                        END IF
                        IF RIGHT$(Temp2$, 1) = CHR$(13) THEN
                            Temp2$ = LEFT$(Temp2$, LEN(Temp2$) - 1)
                        END IF
                        Strngs$(Variable) = Temp2$
                    END IF
                END IF
            CASE 3
                IF RIGHT$(Temp1$, 2) = "()" THEN
                    Temp1$ = LEFT$(Temp1$, 1)
                    IF Temp1$ >= "A" AND Temp1$ <= "Z" THEN
                        Variable = ASC(Temp1$) - 64
                        LINE INPUT #FileNum%, Temp2$
                        IF RIGHT$(Temp2$, 1) = CHR$(10) THEN
                            Temp2$ = LEFT$(Temp2$, LEN(Temp2$) - 1)
                        END IF
                        IF RIGHT$(Temp2$, 1) = CHR$(13) THEN
                            Temp2$ = LEFT$(Temp2$, LEN(Temp2$) - 1)
                        END IF
                        FOR Temp = 1 TO LEN(Temp2$)
                            Arrays(Variable, Temp) = ASC(MID$(Temp2$, Temp, 1))
                            IF Temp >= MaxArrays THEN
                                EXIT FOR
                            END IF
                        NEXT
                    END IF
                END IF
            CASE ELSE
                Out2 = MID$(Temp1$, 2)
                Temp1$ = LEFT$(Temp1$, 1)
                IF Temp1$ >= "A" AND Temp1$ <= "Z" THEN
                    Variable = ASC(Temp1$) - 64
                    CALL Equate(Temp3#)
                    Element = CINT(Temp3#)
                    IF Element > False AND Element <= MaxArrays THEN
                        LINE INPUT #FileNum%, Temp2$
                        IF RIGHT$(Temp2$, 1) = CHR$(10) THEN
                            Temp2$ = LEFT$(Temp2$, LEN(Temp2$) - 1)
                        END IF
                        IF RIGHT$(Temp2$, 1) = CHR$(13) THEN
                            Temp2$ = LEFT$(Temp2$, LEN(Temp2$) - 1)
                        END IF
                        Arrays(Variable, Element) = VAL(Temp2$)
                    ELSE
                        ERROR 9
                    END IF
                END IF
        END SELECT
        EXIT SUB
    END IF
    ERROR 36
END SUB

SUB InputExpression (Var)
    AllowExtra = 1
    IF Var = 1 THEN
        AddCursor = False
        Temp1$ = MID$(Out2, 7)
    ELSE
        AddCursor = True
        Temp1$ = MID$(Out2, 6)
    END IF
    Temp1$ = STRIM$(Temp1$)
    TokenIndex = 1
    Out2 = Temp1$
    LastToken = True
    Quotes = False
    CALL GetToken
    CALL Parse1(Temp3#)
    IF LastToken = False THEN
        IF Quotes THEN
            IF Strng = ";" THEN
                PRINT Out3;
            ELSE
                IF Strng = "," THEN
                    PRINT Out3; "?";
                END IF
            END IF
            Out2 = MID$(Temp1$, TokenIndex)
        ELSE
            Out2 = Temp1$
            PRINT "?";
        END IF
    ELSE
        Out2 = Temp1$
        PRINT "?";
    END IF
    LOCATE , , Visible
    LINE INPUT ; User.Input$
    Stored.Input$ = User.Input$
    StoredTokenIndex = 1
    StoredOut2$ = STRIM$(UCASE$(Out2))
    DO
        TokenIndex = StoredTokenIndex
        Out2 = StoredOut2$
        LastToken = False
        CALL GetToken
        StoredTokenIndex = TokenIndex
        StoredOut2$ = Out2
        Temp1$ = STRIM$(Strng)
        IF LEFT$(Temp1$, 1) >= "A" AND LEFT$(Temp1$, 1) <= "Z" THEN
            Variable = ASC(LEFT$(Temp1$, 1)) - 64
            Out2 = Stored.Input$
            LastToken = False
            TokenIndex = 1
            Temp3# = Dfalse
            DO
                CALL GetToken
                LastTokenType = Token
                IF Token = 1 THEN
                    IF Strng = "," THEN
                        LastTokenType = PrevTokenType
                        Out3 = LEFT$(Out2, TokenIndex - 2)
                        EXIT DO
                    END IF
                END IF
                IF TokenIndex > LEN(Out2) THEN
                    Out3 = Out2
                    EXIT DO
                END IF
                PrevTokenType = LastTokenType
            LOOP
            Temp3# = VAL(Out3)
            IF Stored.Input$ = Nul THEN
                ERROR 136
            END IF
            Stored.Input$ = MID$(Out2, TokenIndex)
            TokenIndex = StoredTokenIndex
            Out2 = StoredOut2$
            SELECT CASE LEN(Temp1$)
                CASE 1
                    IF MID$(Out2, TokenIndex, 1) = "(" THEN
                        IF MID$(Out2, TokenIndex + 1, 1) = ")" THEN
                            CALL GetToken
                            CALL GetToken
                            StoredTokenIndex = TokenIndex
                            StoredOut2$ = Out2
                            FOR Element = 1 TO LEN(Out3)
                                Arrays(Variable, Element) = ASC(MID$(Out3, Element, 1))
                                IF Element >= MaxArrays THEN
                                    EXIT FOR
                                END IF
                            NEXT
                        ELSE
                            CALL GetToken
                            CALL Parse1(Temp4#)
                            StoredTokenIndex = TokenIndex
                            StoredOut2$ = Out2
                            Element = CINT(Temp4#)
                            IF Element > False AND Element <= MaxArrays THEN
                                IF LastTokenType = 2 THEN
                                    Arrays(Variable, Element) = Temp3#
                                ELSE
                                    DataNumber = DataNumber - 1
                                    ERROR 135
                                END IF
                            ELSE
                                ERROR 9
                            END IF
                        END IF
                    ELSE
                        IF LastTokenType = 2 THEN
                            Variables(Variable) = Temp3#
                        ELSE
                            DataNumber = DataNumber - 1
                            ERROR 135
                        END IF
                    END IF
                CASE 2
                    IF MID$(Temp1$, 2, 1) = "$" THEN
                        Strngs$(Variable) = Out3
                    ELSE
                        ERROR 134
                    END IF
                CASE ELSE
                    ERROR 134
            END SELECT
        ELSE
            IF Temp1$ <> "," THEN
                ERROR 134
            END IF
        END IF
        IF StoredTokenIndex > LEN(StoredOut2$) THEN
            EXIT DO
        END IF
    LOOP
    IF Stored.Input$ <> Nul THEN
        ERROR 137
    END IF
    IF AddCursor THEN
        PRINT
    END IF
END SUB

SUB InputExpressionFile
    AllowExtra = 1
    Out2 = MID$(Out2, 8)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    FileNum% = CINT(Temp3#)
    IF FileNum% <= 0 OR FileNum% > MaxFiles THEN
        ERROR 126
        EXIT SUB
    END IF
    IF Strng = "," THEN
        Out2 = MID$(Out2, TokenIndex)
        Out2 = STRIM$(Out2)
        DO
            LastToken = False
            TokenIndex = 1
            CALL GetToken
            IF Strng = "," THEN
                CALL GetToken
            END IF
            Temp1$ = STRIM$(Strng)
            Temp1$ = UCASE$(Temp1$)
            IF LEFT$(Temp1$, 1) >= "A" AND LEFT$(Temp1$, 1) <= "Z" THEN
                Variable = ASC(LEFT$(Temp1$, 1)) - 64
                SELECT CASE LEN(Temp1$)
                    CASE 1
                        IF MID$(Out2, TokenIndex, 1) = "(" THEN
                            IF MID$(Out2, TokenIndex + 1, 1) = ")" THEN
                                INPUT #FileNum%, Out3
                                FOR Element = 1 TO LEN(Out3)
                                    Arrays(Variable, Element) = ASC(MID$(Out3, Element, 1))
                                    IF Element >= MaxArrays THEN
                                        EXIT FOR
                                    END IF
                                NEXT
                            ELSE
                                CALL GetToken
                                CALL Parse1(Temp4#)
                                Element = CINT(Temp4#)
                                INPUT #FileNum%, Temp3#
                                IF Element > False AND Element <= MaxArrays THEN
                                    Arrays(Variable, Element) = Temp3#
                                ELSE
                                    ERROR 9
                                END IF
                            END IF
                        ELSE
                            INPUT #FileNum, Temp3#
                            Variables(Variable) = Temp3#
                        END IF
                    CASE 2
                        IF MID$(Temp1$, 2, 1) = "$" THEN
                            INPUT #FileNum%, Out3
                            IF LEFT$(Out3, 1) = Quote THEN
                                Out3 = MID$(Out3, 2)
                            END IF
                            IF RIGHT$(Out3, 1) = Quote THEN
                                Out3 = LEFT$(Out3, LEN(Out3) - 1)
                            END IF
                            Strngs$(Variable) = Out3
                        ELSE
                            ERROR 134
                        END IF
                    CASE ELSE
                        ERROR 134
                END SELECT
            ELSE
                IF Temp1$ <> "," THEN
                    ERROR 134
                END IF
            END IF
            IF TokenIndex > LEN(Out2) THEN
                EXIT DO
            END IF
            Out2 = MID$(Out2, TokenIndex)
        LOOP
        EXIT SUB
    END IF
    ERROR 34
END SUB

SUB WriteExpression
    AllowExtra = True
    Printing = True
    LastToken = False
    Out3 = Nul
    Out4 = Nul
    TokenIndex = 1

    IF RIGHT$(Out2, 1) = ";" OR RIGHT$(Out2, 1) = "," THEN
        LineFeed = True
        Out2 = LEFT$(Out2, LEN(Out2) - 1)
    ELSE
        LineFeed = False
    END IF
    Out2 = Out2 + ","

    PrinterLF = -2
    Out2 = MID$(Out2, 6)
    Out2 = STRIM$(Out2)
    DO
        LastToken = False
        CALL GetToken
        CALL Parse1(Temp3#)
        IF ErrorValue THEN
            ErrorValue = 0
            EXIT SUB
        END IF
        SELECT CASE Strng
            CASE ",", ";"
                SELECT CASE LastToken
                    CASE -1
                        Var$ = STRIM$(STR$(Temp3#))
                        FOR Var = 1 TO LEN(Var$)
                            PRINT MID$(Var$, Var, 1);
                        NEXT
                    CASE 0
                        Var$ = Quote + Out3 + Quote
                        FOR Var = 1 TO LEN(Var$)
                            PRINT MID$(Var$, Var, 1);
                        NEXT
                END SELECT
            CASE ELSE
                IF LEN(Strng) THEN
                    Strng = "<extra token>"
                    ERROR 92
                END IF
                EXIT DO
        END SELECT
        IF TokenIndex > LEN(Out2) THEN
            EXIT DO
        END IF
        PRINT ",";
    LOOP
    IF LineFeed THEN
        PRINT ",";
    END IF
    IF LineFeed = False THEN
        PRINT
    END IF
    PrinterLF = False
    Printing = False
END SUB

SUB WriteExpressionFile
    AllowExtra = True
    Out2 = MID$(Out2, 8)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    FileNum% = CINT(Temp3#)
    IF FileNum% <= 0 OR FileNum% > MaxFiles THEN
        ERROR 126
        EXIT SUB
    END IF
    IF Strng = "," THEN
        Out2 = MID$(Out2, TokenIndex)
        Out2 = STRIM$(Out2)
        LastToken = False
        Out3 = Nul
        Out4 = Nul
        TokenIndex = 1

        IF RIGHT$(Out2, 1) = ";" OR RIGHT$(Out2, 1) = "," THEN
            LineFeed = True
            Out2 = LEFT$(Out2, LEN(Out2) - 1)
        ELSE
            LineFeed = False
        END IF
        Out2 = Out2 + ","

        DO
            LastToken = False
            CALL GetToken
            CALL Parse1(Temp3#)
            IF ErrorValue THEN
                ErrorValue = 0
                EXIT SUB
            END IF
            SELECT CASE Strng
                CASE ",", ";"
                    SELECT CASE LastToken
                        CASE -1
                            Var$ = STRIM$(STR$(Temp3#))
                            FOR Var = 1 TO LEN(Var$)
                                PRINT #FileNum%, MID$(Var$, Var, 1);
                            NEXT
                        CASE 0
                            Var$ = Quote + Out3 + Quote
                            FOR Var = 1 TO LEN(Var$)
                                PRINT #FileNum%, MID$(Var$, Var, 1);
                            NEXT
                    END SELECT
                CASE ELSE
                    IF LEN(Strng) THEN
                        Strng = "<extra token>"
                        ERROR 92
                    END IF
                    EXIT DO
            END SELECT
            IF TokenIndex > LEN(Out2) THEN
                EXIT DO
            END IF
            PRINT #FileNum%, ",";
        LOOP
        IF LineFeed THEN
            PRINT #FileNum%, ",";
        END IF
        IF LineFeed = False THEN
            PRINT #FileNum%, CHR$(13); CHR$(10);
        END IF
        EXIT SUB
    END IF
    ERROR 31
END SUB

SUB ChangeColor
    Out2 = MID$(Out2, 6)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp4#)
    Foreground = CINT(Temp4#)
    IF Strng = "," THEN
        CALL GetToken
        CALL Parse1(Temp4#)
        BackGround = CINT(Temp4#)
        COLOR Foreground, BackGround
        LastColor1 = Foreground
        LastColor2 = BackGround
        EXIT SUB
    END IF
    COLOR Foreground
    LastColor1 = Foreground
END SUB

SUB LockFile ' lock #
    Out2 = MID$(Out2, 7)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp4#)
    Filen% = CINT(Temp4#)
    IF Strng = "," THEN
        CALL GetToken
        CALL Parse1(Temp4#)
        Filerec% = CINT(Temp4#)
        IF Strng = "," THEN
            CALL GetToken
            CALL Parse1(Temp4#)
            Filerec2% = CINT(Temp4#)
            LOCK Filen%, Filerec% TO Filerec2%
        ELSE
            LOCK Filen%, Filerec%
        END IF
        EXIT SUB
    END IF
    LOCK Filen%
END SUB

SUB UnlockFile ' unlock #
    Out2 = MID$(Out2, 9)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp4#)
    Filen% = CINT(Temp4#)
    IF Strng = "," THEN
        CALL GetToken
        CALL Parse1(Temp4#)
        Filerec% = CINT(Temp4#)
        IF Strng = "," THEN
            CALL GetToken
            CALL Parse1(Temp4#)
            Filerec2% = CINT(Temp4#)
            UNLOCK Filen%, Filerec% TO Filerec2%
        ELSE
            UNLOCK Filen%, Filerec%
        END IF
        EXIT SUB
    END IF
    UNLOCK Filen%
END SUB

' special print function requires:
'    Print Using (<x>,"x"), (<x>,"x"), ...
SUB PrintUsing
    AllowExtra = True
    Printing = True
    LastToken = False
    Out3 = Nul
    Out4 = Nul
    Temp# = False
    TokenIndex = 1
    Out2 = MID$(Out2, 12)
    Out2 = STRIM$(Out2)
    Out2 = XTRIM$(Out2, True)

    IF RIGHT$(Out2, 1) = ";" OR RIGHT$(Out2, 1) = "," THEN
        LineFeed = True
    ELSE
        LineFeed = False
    END IF

    PrinterLF = 1
    DO
        LastToken = False
        CALL GetToken
        IF Strng <> "(" THEN
            Strng = "<missing left token>"
            ERROR 92
            EXIT SUB
        END IF
        CALL GetToken
        CALL Parse1(Temp3#)
        IF ErrorValue THEN
            ErrorValue = 0
            EXIT SUB
        END IF
        Number# = Temp3#
        CALL GetToken
        CALL Parse1(Temp3#)
        IF ErrorValue THEN
            ErrorValue = 0
            EXIT SUB
        END IF
        Strng = MID$(Out2, TokenIndex, 1)
        TokenIndex = TokenIndex + 1
        SELECT CASE Strng
            CASE ","
                SELECT CASE LastToken
                    CASE -1
                        Strng = "<string error>"
                        ERROR 92
                    CASE 0
                        PRINT USING Out3; Number#;
                        PRINT , " ";
                    CASE ELSE
                        PRINT "",
                END SELECT
            CASE ";"
                SELECT CASE LastToken
                    CASE -1
                        Strng = "<string error>"
                        ERROR 92
                    CASE 0
                        PRINT USING Out3; Number#;
                    CASE ELSE
                        PRINT "";
                END SELECT
            CASE ELSE
                IF LEN(Strng) THEN
                    Strng = "<extra token>"
                    ERROR 92
                END IF
                SELECT CASE LastToken
                    CASE -1
                        Strng = "<string error>"
                        ERROR 92
                    CASE 0
                        PRINT USING Out3; Number#;
                    CASE ELSE
                        PRINT "";
                END SELECT
                EXIT DO
        END SELECT
        IF TokenIndex > LEN(Out2) THEN
            EXIT DO
        END IF
    LOOP
    IF RIGHT$(Out2, 1) = ";" OR RIGHT$(Out2, 1) = "," THEN
        Out2 = LEFT$(Out2, LEN(Out2) - 1)
    END IF
    IF RIGHT$(Out2, 1) <> ")" THEN
        Strng = "<missing right token>"
        ERROR 92
        EXIT SUB
    END IF
    IF LineFeed = False THEN
        PRINT
    END IF
    PrinterLF = False
    Printing = False
END SUB

' special lprint function requires:
'    Lprint Using (<x>,"x"), (<x>,"x"), ...
SUB LprintUsing
    AllowExtra = True
    Printing = True
    LastToken = False
    Out3 = Nul
    Out4 = Nul
    Temp# = False
    TokenIndex = 1
    Out2 = MID$(Out2, 13)
    Out2 = STRIM$(Out2)
    Out2 = XTRIM$(Out2, True)

    IF RIGHT$(Out2, 1) = ";" OR RIGHT$(Out2, 1) = "," THEN
        LineFeed = True
    ELSE
        LineFeed = False
    END IF

    PrinterLF = True
    DO
        LastToken = False
        CALL GetToken
        IF Strng <> "(" THEN
            Strng = "<missing left token>"
            ERROR 92
            EXIT SUB
        END IF
        CALL GetToken
        CALL Parse1(Temp3#)
        IF ErrorValue THEN
            ErrorValue = 0
            EXIT SUB
        END IF
        Number# = Temp3#
        CALL GetToken
        CALL Parse1(Temp3#)
        IF ErrorValue THEN
            ErrorValue = 0
            EXIT SUB
        END IF
        Strng = MID$(Out2, TokenIndex, 1)
        TokenIndex = TokenIndex + 1
        SELECT CASE Strng
            CASE ","
                SELECT CASE LastToken
                    CASE -1
                        Strng = "<string error>"
                        ERROR 92
                    CASE 0
                        LPRINT USING Out3; Number#;
                        LPRINT , " ";
                    CASE ELSE
                        LPRINT "",
                END SELECT
            CASE ";"
                SELECT CASE LastToken
                    CASE -1
                        Strng = "<string error>"
                        ERROR 92
                    CASE 0
                        LPRINT USING Out3; Number#;
                    CASE ELSE
                        LPRINT "";
                END SELECT
            CASE ELSE
                IF LEN(Strng) THEN
                    Strng = "<extra token>"
                    ERROR 92
                END IF
                SELECT CASE LastToken
                    CASE -1
                        Strng = "<string error>"
                        ERROR 92
                    CASE 0
                        LPRINT USING Out3; Number#;
                    CASE ELSE
                        LPRINT "";
                END SELECT
                EXIT DO
        END SELECT
        IF TokenIndex > LEN(Out2) THEN
            EXIT DO
        END IF
    LOOP
    IF RIGHT$(Out2, 1) = ";" OR RIGHT$(Out2, 1) = "," THEN
        Out2 = LEFT$(Out2, LEN(Out2) - 1)
    END IF
    IF RIGHT$(Out2, 1) <> ")" THEN
        Strng = "<missing right token>"
        ERROR 92
        EXIT SUB
    END IF
    IF LineFeed = False THEN
        LPRINT
    END IF
    PrinterLF = False
    Printing = False
END SUB

SUB ChangeScreen
    AllowExtra = True
    ScreenColor = False
    ColorSet = False
    ActivePage = False
    ActiveSet = False
    VisualPage = False
    VisualSet = False
    Out2 = MID$(Out2, 7)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp4#)
    ScreenMode = CINT(Temp4#)
    IF Strng = "," THEN
        CALL GetToken
        CALL Parse1(Temp4#)
        ScreenColor = CINT(Temp4#)
        IF LastToken THEN
            ColorSet = True
        END IF
        IF Strng = "," THEN
            CALL GetToken
            CALL Parse1(Temp4#)
            ActivePage = CINT(Temp4#)
            IF LastToken THEN
                ActiveSet = True
            END IF
            IF Strng = "," THEN
                CALL GetToken
                CALL Parse1(Temp4#)
                VisualPage = CINT(Temp4#)
                IF LastToken THEN
                    VisualSet = True
                END IF
            END IF
        END IF
    END IF
    IF ColorSet AND ActiveSet AND VisualSet THEN
        SCREEN ScreenMode, ScreenColor, ActivePage, VisualPage
        LastScreen1 = ScreenMode
        LastScreen2 = ScreenColor
        LastScreen3 = ActivePage
        LastScreen4 = VisualPage
    ELSE
        IF ColorSet AND ActiveSet THEN
            SCREEN ScreenMode, ScreenColor, ActivePage
            LastScreen1 = ScreenMode
            LastScreen2 = ScreenColor
            LastScreen3 = ActivePage
        ELSE
            IF ColorSet AND VisualSet THEN
                SCREEN ScreenMode, ScreenColor, , VisualPage
                LastScreen1 = ScreenMode
                LastScreen2 = ScreenColor
                LastScreen4 = VisualPage
            ELSE
                IF ActiveSet AND VisualSet THEN
                    SCREEN ScreenMode, , ActivePage, VisualPage
                    LastScreen1 = ScreenMode
                    LastScreen3 = ActivePage
                    LastScreen4 = VisualPage
                ELSE
                    IF ColorSet THEN
                        SCREEN ScreenMode, ScreenColor
                        LastScreen1 = ScreenMode
                        LastScreen2 = ScreenColor
                    ELSE
                        IF ActiveSet THEN
                            SCREEN ScreenMode, , ActivePage
                            LastScreen1 = ScreenMode
                            LastScreen3 = ActivePage
                        ELSE
                            IF VisualSet THEN
                                SCREEN ScreenMode, , , VisualPage
                                LastScreen1 = ScreenMode
                                LastScreen4 = VisualPage
                            ELSE
                                SCREEN ScreenMode
                                LastScreen1 = ScreenMode
                            END IF
                        END IF
                    END IF
                END IF
            END IF
        END IF
    END IF
END SUB

SUB ChangeWidth
    Out2 = MID$(Out2, 6)
    Out2 = STRIM$(Out2)
    IF LEFT$(Out2, 1) = "#" THEN
        Out2 = MID$(Out2, 2)
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp4#)
        FileNumber = CINT(Temp4#)
        IF Strng = "," THEN
            CALL GetToken
            CALL Parse1(Temp4#)
            FileWidth = CINT(Temp4#)
            WIDTH #FileNumber, FileWidth
            EXIT SUB
        END IF
    ELSE
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp4#)
        IF LastToken THEN
            ScreenWidth = CINT(Temp4#)
            IF Strng = "," THEN
                CALL GetToken
                CALL Parse1(Temp4#)
                ScreenHeight = CINT(Temp4#)
                SELECT CASE ScreenWidth
                    CASE 40, 80
                        SELECT CASE ScreenHeight
                            CASE 25, 30, 43, 50, 60
                                WIDTH ScreenWidth, ScreenHeight
                                LastWidth1 = ScreenWidth
                                LastWidth2 = ScreenHeight
                                EXIT SUB
                        END SELECT
                END SELECT
            END IF
        ELSE
            Device$ = Out3
            IF Strng = "," THEN
                CALL GetToken
                CALL Parse1(Temp4#)
                DeviceWidth = CINT(Temp4#)
                IF UCASE$(Device$) = "LPRINT" THEN
                    WIDTH LPRINT DeviceWidth
                    EXIT SUB
                ELSE
                    ' WIDTH Device$, DeviceWidth
                    '   not suppoerted in QB64
                    ERROR 73 ' feature unavailable.
                    EXIT SUB
                END IF
            END IF
        END IF
    END IF
    ERROR 146
END SUB

SUB SoundSpeaker
    Out2 = MID$(Out2, 6)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp4#)
    Tone = CINT(Temp4#)
    IF Strng = "," THEN
        CALL GetToken
        CALL Parse1(Temp4#)
        Duration = CINT(Temp4#)
        SOUND Tone, Duration
        EXIT SUB
    END IF
    ERROR 147
END SUB

SUB LocateCursor
    AllowExtra = True
    Out2 = MID$(Out2, 7)
    Out2 = STRIM$(Out2)
    Xcoor = CSRLIN
    Ycoor = POS(0)
    IF LEN(Out2) THEN
        TokenIndex = 1
        IF MID$(Out2, TokenIndex, 1) = "," THEN
            CALL GetToken
        ELSE
            CALL GetToken
            CALL Parse1(Temp4#)
            Xcoor = CINT(Temp4#)
        END IF
        IF Strng = "," THEN
            IF MID$(Out2, TokenIndex, 1) = "," THEN
                CALL GetToken
            ELSE
                CALL GetToken
                CALL Parse1(Temp4#)
                Ycoor = CINT(Temp4#)
            END IF
            IF Strng = "," THEN
                IF MID$(Out2, TokenIndex, 1) = "," THEN
                    CALL GetToken
                ELSE
                    CALL GetToken
                    CALL Parse1(Temp4#)
                    Visible = CINT(Temp4#)
                END IF
                IF Strng = "," THEN
                    CALL GetToken
                    CALL Parse1(Temp4#)
                    StartScan = CINT(Temp4#)
                    EndScan = StartScan
                    IF Strng = "," THEN
                        CALL GetToken
                        CALL Parse1(Temp4#)
                        EndScan = CINT(Temp4#)
                    END IF
                    LOCATE Xcoor, Ycoor, Visible, StartScan, EndScan
                    LastCursor1 = Visible
                    LastCursor2 = StartScan
                    LastCursor3 = EndScan
                    EXIT SUB
                END IF
            END IF
        END IF
    END IF
    LOCATE Xcoor, Ycoor, Visible
    LastCursor1 = Visible
END SUB

SUB CLSScreen
    Out2 = MID$(Out2, 4)
    Out2 = STRIM$(Out2)
    IF LEN(Out2) THEN
        '   CLSType = INT(VAL(Out2))
        SELECT CASE Out2
            CASE "0"
                CLS 0
            CASE "1"
                CLS 1
            CASE "2"
                CLS 2
            CASE ELSE
                ERROR 2
        END SELECT
        EXIT SUB
    END IF
    CLS
END SUB

SUB BSaveImage
    Out2 = MID$(Out2, 6)
    Out2 = STRIM$(Out2)
    Filename$ = Nul
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    IF LastToken = False THEN
        Filename$ = DRX + Out3 + ".sc2"
        IF Strng = "," THEN
            CALL GetToken
            CALL Parse1(Temp3#)
            Offset = CINT(Temp3#)
            IF Strng = "," THEN
                CALL GetToken
                CALL Parse1(Temp3#)
                Length = CINT(Temp3#)
                BSAVE Filename$, Offset, Length
                EXIT SUB
            END IF
        END IF
    END IF
    ERROR 60
END SUB

SUB BLoadImage
    Out2 = MID$(Out2, 6)
    Out2 = STRIM$(Out2)
    Filename$ = Nul
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    IF LastToken = False THEN
        Filename$ = DRX + Out3 + ".sc2"
        IF Strng = "," THEN
            CALL GetToken
            CALL Parse1(Temp3#)
            Offset = CINT(Temp3#)
            BLOAD Filename$, Offset
        ELSE
            BLOAD Filename$
        END IF
        EXIT SUB
    END IF
    ERROR 60
END SUB

SUB DrawPixel
    Out2 = MID$(Out2, 5)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    X% = CINT(Temp3#)
    IF Strng = "," THEN
        CALL GetToken
        CALL Parse1(Temp3#)
        Y% = CINT(Temp3#)
        IF Strng = "," THEN
            CALL GetToken
            CALL Parse1(Temp3#)
            C% = CINT(Temp3#)
            PSET (X%, Y%), C%
            EXIT SUB
        ELSE
            PSET (X%, Y%)
            EXIT SUB
        END IF
    END IF
    ERROR 15
END SUB

SUB DrawPixelStep
    Out2 = MID$(Out2, 10)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    X% = CINT(Temp3#)
    IF Strng = "," THEN
        CALL GetToken
        CALL Parse1(Temp3#)
        Y% = CINT(Temp3#)
        IF Strng = "," THEN
            CALL GetToken
            CALL Parse1(Temp3#)
            C% = CINT(Temp3#)
            PSET STEP(X%, Y%), C%
            EXIT SUB
        ELSE
            PSET STEP(X%, Y%)
            EXIT SUB
        END IF
    END IF
    ERROR 15
END SUB

SUB DrawPixelX
    Out2 = MID$(Out2, 7)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    X% = CINT(Temp3#)
    IF Strng = "," THEN
        CALL GetToken
        CALL Parse1(Temp3#)
        Y% = CINT(Temp3#)
        IF Strng = "," THEN
            CALL GetToken
            CALL Parse1(Temp3#)
            C% = CINT(Temp3#)
            PRESET (X%, Y%), C%
            EXIT SUB
        ELSE
            PRESET (X%, Y%)
            EXIT SUB
        END IF
    END IF
    ERROR 15
END SUB

SUB DrawPixelXStep
    Out2 = MID$(Out2, 12)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    X% = CINT(Temp3#)
    IF Strng = "," THEN
        CALL GetToken
        CALL Parse1(Temp3#)
        Y% = CINT(Temp3#)
        IF Strng = "," THEN
            CALL GetToken
            CALL Parse1(Temp3#)
            C% = CINT(Temp3#)
            PRESET STEP(X%, Y%), C%
            EXIT SUB
        ELSE
            PRESET STEP(X%, Y%)
            EXIT SUB
        END IF
    END IF
    ERROR 15
END SUB

SUB DrawExpression
    Out2 = MID$(Out2, 5)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    IF LastToken = False THEN
        DRAW Out3
        EXIT SUB
    END IF
    ERROR 46
END SUB

SUB PlayExpression
    Out2 = MID$(Out2, 5)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    IF LastToken = False THEN
        PLAY Out3
        EXIT SUB
    END IF
    ERROR 47
END SUB

SUB RestoreData
    Out2 = MID$(Out2, 8)
    Out2 = STRIM$(Out2)

    ' search first data statement
    IF LEN(Out2) = False THEN
        FOR LineNumber% = 1 TO LastLine
            Out2 = Program$(LineNumber%)
            Out2 = STRIM$(Out2)
            Out2 = UCASE$(Out2)
            IF LEFT$(Out2, 4) = "DATA" THEN
                DataLine = LineNumber%
                DataNumber = False
                EXIT FOR
            END IF
        NEXT
        EXIT SUB
    END IF

    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#) ' allow equation in RESTORE statement!?
    IF LastToken = True THEN
        LineNumber% = CINT(Temp3#)
        IF LineNumber% = -1 THEN ' move back
            IF DataLine > 0 THEN
                FOR V = DataLine - 1 TO 1 STEP -1
                    Out2 = Program$(V)
                    Out2 = STRIM$(Out2)
                    Out2 = UCASE$(Out2)
                    IF LEFT$(Out2, 4) = "DATA" THEN
                        DataLine = V
                        DataNumber = False
                        EXIT SUB
                    END IF
                NEXT
            END IF
            EXIT SUB
        END IF
        IF LineNumber% >= 1 AND LineNumber% <= LastLine THEN
            Out2 = Program$(LineNumber%)
            Out2 = STRIM$(Out2)
            Out2 = UCASE$(Out2)
            IF LEFT$(Out2, 4) = "DATA" THEN
                DataLine = LineNumber%
                DataNumber = False
                EXIT SUB
            END IF
        END IF
    END IF
    ERROR 65
END SUB

SUB ReadData
    AllowExtra = 1
    Out2 = MID$(Out2, 5)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    DO
        LastToken = False
        CALL GetToken
        Temp1$ = STRIM$(Strng)
        Temp1$ = UCASE$(Temp1$)
        IF LEFT$(Temp1$, 1) >= "A" AND LEFT$(Temp1$, 1) <= "Z" THEN
            Variable = ASC(LEFT$(Temp1$, 1)) - 64
            SELECT CASE LEN(Temp1$)
                CASE 1
                    IF MID$(Out2, TokenIndex, 1) = "(" THEN
                        IF MID$(Out2, TokenIndex + 1, 1) = ")" THEN
                            CALL GetToken
                            CALL GetToken
                            CALL ReadDataElement(Var)
                            IF Var THEN
                                ERROR 66
                            END IF
                            IF LastToken = False THEN
                                FOR Element = 1 TO LEN(Out3)
                                    Arrays(Variable, Element) = ASC(MID$(Out3, Element, 1))
                                    IF Element >= MaxArrays THEN
                                        EXIT FOR
                                    END IF
                                NEXT
                            ELSE
                                Arrays(Variable, 1) = DataValue
                            END IF
                        ELSE
                            CALL GetToken
                            CALL Parse1(Temp4#)
                            Element = CINT(Temp4#)
                            CALL ReadDataElement(Var)
                            IF Var THEN
                                ERROR 66
                            END IF
                            IF LastToken THEN
                                IF Element > False AND Element <= MaxArrays THEN
                                    Arrays(Variable, Element) = DataValue
                                ELSE
                                    ERROR 9
                                END IF
                            ELSE
                                IF Out3 = Nul THEN
                                    IF Element > False AND Element <= MaxArrays THEN
                                        Arrays(Variable, Element) = 0#
                                    ELSE
                                        ERROR 9
                                    END IF
                                ELSE
                                    DataNumber = DataNumber - 1
                                    ERROR 135
                                END IF
                            END IF
                        END IF
                    ELSE
                        CALL ReadDataElement(Var)
                        IF Var THEN
                            ERROR 66
                        END IF
                        IF LastToken THEN
                            Variables(Variable) = DataValue
                        ELSE
                            IF Out3 = Nul THEN
                                Variables(Variable) = 0#
                            ELSE
                                DataNumber = DataNumber - 1
                                ERROR 135
                            END IF
                        END IF
                    END IF
                CASE 2
                    IF MID$(Temp1$, 2, 1) = "$" THEN
                        CALL ReadDataElement(Var)
                        IF Var THEN
                            ERROR 66
                        END IF
                        IF LastToken = False THEN
                            Strngs$(Variable) = Out3
                        ELSE
                            Strngs(Variable) = LTRIM$(STR$(DataValue))
                        END IF
                    ELSE
                        ERROR 134
                    END IF
                CASE ELSE
                    ERROR 134
            END SELECT
        ELSE
            IF Temp1$ = "," OR Temp1$ = ";" THEN
                Eat$ = Nul
            ELSE
                ERROR 134
            END IF
        END IF
        IF TokenIndex > LEN(Out2) THEN
            EXIT DO
        END IF
    LOOP
END SUB

SUB ReadRecord
    Out2 = MID$(Out2, 7)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    FieldRead = False
    FileNum% = CINT(Temp3#)
    IF FileNum% <= 0 OR FileNum% > MaxFiles THEN
        ERROR 126
        EXIT SUB
    END IF
    IF Strng = "," THEN
        Temp1$ = MID$(Out2, TokenIndex)
        Temp1$ = STRIM$(Temp1$)
        Temp1$ = UCASE$(Temp1$)
        Temp2$ = LEFT$(Temp1$, 1)
        Temp1$ = MID$(Temp1$, 2)
        IF Temp1$ = "$" THEN
            IF Temp2$ >= "A" AND Temp2$ <= "Z" THEN
                Variable = ASC(Temp2$) - 64
                Out2 = FieldArray$(FileNum%)
                Out2 = STRIM$(Out2)
                Out2 = UCASE$(Out2)
                TokenIndex = 1
                Start% = 1
                DO
                    CALL GetToken
                    CALL Parse1(Temp3#)
                    Length% = CINT(Temp3#)
                    FieldVariable = False
                    IF Strng = "AS" THEN
                        Out2 = MID$(Out2, TokenIndex + 1)
                        Out2 = STRIM$(Out2)
                        IF LEFT$(Out2, 1) >= "A" AND LEFT$(Out2, 1) <= "Z" THEN
                            IF MID$(Out2, 2, 1) = "$" THEN
                                FieldVariable = ASC(LEFT$(Out2, 1)) - 64
                                Out2 = MID$(Out2, 4)
                            END IF
                        END IF
                        TokenIndex = 1
                    END IF
                    IF Strng = "," THEN
                        Out2 = MID$(Out2, TokenIndex + 1)
                        TokenIndex = 1
                    END IF
                    IF FieldVariable = Variable THEN
                        FieldRead = True
                        Temp$ = MID$(FileFields$(FileNum%), Start%, Length%)
                        Strngs$(Variable) = Temp$
                    END IF
                    IF FieldVariable THEN
                        Start% = Start% + Length%
                    END IF
                    IF TokenIndex > LEN(Out2) THEN
                        EXIT DO
                    END IF
                LOOP
            END IF
        END IF
    END IF
    IF FieldRead = False THEN
        ERROR 45
    END IF
END SUB

SUB GetRecord
    Out2 = MID$(Out2, 6)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    FileNum% = CINT(Temp3#)
    IF FileNum% <= 0 OR FileNum% > MaxFiles THEN
        ERROR 126
        EXIT SUB
    END IF
    IF Strng = "," THEN
        CALL GetToken
        CALL Parse1(Temp4#)
        RecordNumber! = CSNG(Temp4#)
        IF Strng = "," THEN
            Temp1$ = MID$(Out2, TokenIndex)
            Temp1$ = STRIM$(Temp1$)
            Temp1$ = UCASE$(Temp1$)
            Temp2$ = LEFT$(Temp1$, 1)
            Temp1$ = MID$(Temp1$, 2)
            IF LEFT$(Temp1$, 1) = "$" THEN
                IF Temp2$ >= "A" AND Temp2$ <= "Z" THEN
                    Variable = ASC(Temp2$) - 64
                    IF RecordNumber! = 0! THEN
                        GET #FileNum%, , Strngs$(Variable)
                    ELSE
                        GET #FileNum%, RecordNumber!, Strngs$(Variable)
                    END IF
                    EXIT SUB
                END IF
            END IF
        ELSE
            GET #FileNum%, RecordNumber!
            EXIT SUB
        END IF
    ELSE
        GET #FileNum%
        EXIT SUB
    END IF
    ERROR 44
END SUB

SUB PutRecord
    Out2 = MID$(Out2, 6)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    FileNum% = CINT(Temp3#)
    IF FileNum% <= 0 OR FileNum% > MaxFiles THEN
        ERROR 126
        EXIT SUB
    END IF
    IF Strng = "," THEN
        CALL GetToken
        CALL Parse1(Temp4#)
        RecordNumber! = CSNG(Temp4#)
        IF RecordNumber! > LOF(FileNum%) + 1 THEN
            ERROR 111
            EXIT SUB
        END IF
        IF Strng = "," THEN
            CALL GetToken
            CALL Parse1(Temp4#)
            IF LastToken = False THEN
                IF RecordNumber! = 0! THEN
                    PUT #FileNum%, , Out3
                ELSE
                    PUT #FileNum%, RecordNumber!, Out3
                END IF
            ELSE
                IF RecordNumber! = 0! THEN
                    PUT #FileNum%, , Temp4#
                ELSE
                    PUT #FileNum%, RecordNumber!, Temp4#
                END IF
            END IF
            EXIT SUB
        ELSE
            PUT #FileNum%, RecordNumber!
            EXIT SUB
        END IF
    ELSE
        PUT #FileNum%
        EXIT SUB
    END IF
    ERROR 43
END SUB

SUB FieldSet (Var)
    IF Var = 1 THEN
        FieldType = 1
    ELSE
        FieldType = 2
    END IF
    Out2 = MID$(Out2, 7)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    FieldSet2 = False
    FileNum% = CINT(Temp3#)
    IF FileNum% <= 0 OR FileNum% > MaxFiles THEN
        ERROR 126
        EXIT SUB
    END IF
    IF Strng = "," THEN
        Temp1$ = MID$(Out2, TokenIndex)
        Temp1$ = STRIM$(Temp1$)
        Temp1$ = UCASE$(Temp1$)
        Temp2$ = LEFT$(Temp1$, 1)
        Temp1$ = MID$(Temp1$, 2)
        IF LEFT$(Temp1$, 1) = "$" THEN
            Temp1$ = MID$(Temp1$, 2)
            Temp1$ = STRIM$(Temp1$)
            IF LEFT$(Temp1$, 1) = "," THEN
                IF Temp2$ >= "A" AND Temp2$ <= "Z" THEN
                    Variable = ASC(Temp2$) - 64
                    CALL GetToken
                    CALL Parse1(Temp4#)
                    CALL GetToken
                    CALL Parse1(Temp4#)
                    IF LastToken = False THEN
                        FieldValue$ = Out3
                        Out2 = FieldArray$(FileNum%)
                        Out2 = STRIM$(Out2)
                        Out2 = UCASE$(Out2)
                        TokenIndex = 1
                        Start% = 1
                        DO
                            CALL GetToken
                            CALL Parse1(Temp3#)
                            Length% = CINT(Temp3#)
                            FieldVariable = False
                            IF Strng = "AS" THEN
                                Out2 = MID$(Out2, TokenIndex + 1)
                                Out2 = STRIM$(Out2)
                                IF LEFT$(Out2, 1) >= "A" AND LEFT$(Out2, 1) <= "Z" THEN
                                    IF MID$(Out2, 2, 1) = "$" THEN
                                        FieldVariable = ASC(LEFT$(Out2, 1)) - 64
                                        Out2 = MID$(Out2, 4)
                                    END IF
                                END IF
                                TokenIndex = 1
                            END IF
                            IF Strng = "," THEN
                                Out2 = MID$(Out2, TokenIndex + 1)
                                TokenIndex = 1
                            END IF
                            IF FieldVariable = Variable THEN
                                FieldSet2 = True
                                Temp$ = STRING$(Length%, CHR$(0))
                                IF FieldType = 1 THEN
                                    LSET Temp$ = FieldValue$
                                ELSE
                                    RSET Temp$ = FieldValue$
                                END IF
                                MID$(FileFields$(FileNum%), Start%, Length%) = Temp$
                            END IF
                            IF FieldVariable THEN
                                Start% = Start% + Length%
                            END IF
                            IF TokenIndex > LEN(Out2) THEN
                                EXIT DO
                            END IF
                        LOOP
                    END IF
                END IF
            END IF
        END IF
    END IF
    IF FieldSet2 = False THEN
        IF FieldType = 1 THEN
            ERROR 41
        ELSE
            ERROR 42
        END IF
    END IF
END SUB

SUB OpenField
    Out2 = MID$(Out2, 8)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    FileNum% = CINT(Temp3#)
    IF FileNum% <= 0 OR FileNum% > MaxFiles THEN
        ERROR 126
        EXIT SUB
    END IF
    IF Strng = "," THEN
        Temp1$ = MID$(Out2, TokenIndex)
        Temp1$ = STRIM$(Temp1$)
        FieldArray$(FileNum%) = Temp1$
        EXIT SUB
    END IF
    ERROR 23
END SUB

SUB OpenFile
    Out2 = MID$(Out2, 7)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    FileNum% = CINT(Temp3#)
    IF FileNum% <= 0 OR FileNum% > MaxFiles THEN
        ERROR 126
        EXIT SUB
    END IF
    IF Strng = "," THEN
        CALL GetToken
        CALL Parse1(Temp4#)
        IF LastToken = False THEN
            ProgramFile$ = Out3
            IF Strng = "," THEN
                CALL GetToken
                CALL Parse1(Temp4#)
                IF LastToken = False THEN
                    ProgramType$ = Out3
                    IF Strng = "," THEN
                        CALL GetToken
                        CALL Parse1(Temp4#)
                        Program.Length = CINT(Temp4#)
                    ELSE
                        Program.Length = 128
                    END IF
                    SELECT CASE UCASE$(ProgramType$)
                        CASE "I"
                            OPEN ProgramFile$ FOR INPUT SHARED AS #FileNum% LEN = Program.Length
                        CASE "O"
                            OPEN ProgramFile$ FOR OUTPUT SHARED AS #FileNum% LEN = Program.Length
                        CASE "A"
                            OPEN ProgramFile$ FOR APPEND SHARED AS #FileNum% LEN = Program.Length
                        CASE "R"
                            OPEN ProgramFile$ FOR RANDOM SHARED AS #FileNum% LEN = Program.Length
                            FileFields$(FileNum%) = STRING$(Program.Length, CHR$(0))
                            FIELD #FileNum%, Program.Length AS FileFields$(FileNum%)
                        CASE "B"
                            OPEN ProgramFile$ FOR BINARY SHARED AS #FileNum% LEN = Program.Length
                            FileFields$(FileNum%) = STRING$(Program.Length, CHR$(0))
                        CASE ELSE
                            ERROR 21
                    END SELECT
                    EXIT SUB
                END IF
            END IF
        END IF
    END IF
    ERROR 21
END SUB

SUB CloseFile (Var)
    IF Var = 2 THEN
        CLOSE
        EXIT SUB
    END IF
    Out2 = MID$(Out2, 8)
    Out2 = STRIM$(Out2)
    IF LEN(Out2) THEN
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp3#)
        FileNum% = CINT(Temp3#)
        IF FileNum% <= 0 OR FileNum% > MaxFiles THEN
            ERROR 126
            EXIT SUB
        END IF
        CLOSE #FileNum%
        EXIT SUB
    END IF
    ERROR 22
END SUB

SUB ChainProgram
    Out2 = MID$(Out2, 6)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    IF LastToken = False THEN
        ProgramFile$ = Out3
        StartLine = False
        IF Strng = "," THEN
            CALL GetToken
            CALL Parse1(Temp4#)
            StartLine = CINT(Temp4#) - 1
        END IF
        IF ProgramFile$ <> Nul THEN
            CALL Concatenate(ProgramFile$)
            Filename = ProgramFile$
            IF _FILEEXISTS(Filename) THEN
                IF _FILEEXISTS(PrepareFilename) THEN
                    KILL PrepareFilename
                END IF
                CALL NewProgram
                ProgramName = None
                CALL ReadProgram
                ProgramName = ProgramFile$
                CALL PrepareProgram
                NestedGosub = False
                MaxGosubs = 10
                Visible = 1
                REDIM GosubReturn(1 TO 10) AS INTEGER
                ProgramLine = StartLine
                CALL CountLines(LastLine)
                EXIT SUB
            END IF
        END IF
    END IF
    ERROR 112
END SUB

SUB ShellProgram
    Out2 = MID$(Out2, 6)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    DOSCommand$ = Nul
    IF LEN(Out2) THEN
        CALL GetToken
        CALL Parse1(Temp3#)
        IF LastToken = False THEN
            DOSCommand$ = Out3
        END IF
    END IF
    IF DOSCommand$ = Nul THEN
        COLOR 7, 0
        PRINT "Type 'EXIT' to return."
        SHELL
        EXIT SUB
    END IF
    FX$ = "SIC64.BAT"
    X = FREEFILE
    OPEN FX$ FOR OUTPUT AS #X
    PRINT #X, DOSCommand$
    PRINT #X, "PAUSE"
    PRINT #X, "EXIT"
    CLOSE #X
    SHELL FX$
    KILL FX$
END SUB

' SHELL Param$
SUB ShellProgram2 (Var$)
    IF LEN(Var$) THEN
        FX$ = "SIC64.BAT"
        X = FREEFILE
        OPEN FX$ FOR OUTPUT AS #X
        PRINT #X, Var$
        PRINT #X, "PAUSE"
        PRINT #X, "EXIT"
        CLOSE #X
        SHELL FX$
        KILL FX$
        COLOR White, Black
        PRINT "Returned from DOS shell."
        EXIT SUB
    END IF
    COLOR 7, 0
    PRINT "Type 'EXIT' to return."
    SHELL
    COLOR White, Black
    PRINT "Returned from DOS shell."
END SUB

SUB NameExpression (Var)
    IF Var = 1 THEN
        Out2 = MID$(Out2, 7)
    ELSE
        Out2 = MID$(Out2, 5)
    END IF
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    IF LastToken = False THEN
        ProgramFile$ = Out3
        IF Strng = "," THEN
            CALL GetToken
            CALL Parse1(Temp4#)
            IF LastToken = False THEN
                NAME ProgramFile$ AS Out3
                EXIT SUB
            END IF
        END IF
    END IF
    ERROR 113
END SUB

SUB KillFile (Var)
    IF Var = 1 THEN
        Out2 = MID$(Out2, 5)
    ELSE
        Out2 = MID$(Out2, 7)
    END IF
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    IF LastToken = False THEN
        KILL Out3
        EXIT SUB
    END IF
    ERROR 114
END SUB

SUB CDDirectory (Var)
    IF Var = 1 THEN
        Out2 = MID$(Out2, 3)
    ELSE
        Out2 = MID$(Out2, 6)
    END IF
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    IF LastToken = False THEN
        CHDIR Out3
        EXIT SUB
    END IF
    ERROR 115
END SUB

SUB MDDirectory (Var)
    IF Var = 1 THEN
        Out2 = MID$(Out2, 3)
    ELSE
        Out2 = MID$(Out2, 6)
    END IF
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    IF LastToken = False THEN
        MKDIR Out3
        EXIT SUB
    END IF
    ERROR 116
END SUB

SUB RDDirectory (Var)
    IF Var = 1 THEN
        Out2 = MID$(Out2, 3)
    ELSE
        Out2 = MID$(Out2, 6)
    END IF
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    IF LastToken = False THEN
        RMDIR Out3
        EXIT SUB
    END IF
    ERROR 117
END SUB

SUB SetDate
    Out2 = MID$(Out2, 6)
    Out2 = STRIM$(Out2)
    IF LEFT$(Out2, 1) = "=" THEN
        Out2 = MID$(Out2, 2)
        Out2 = STRIM$(Out2)
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp3#)
        IF LastToken = False THEN
            DATE$ = Out3
            EXIT SUB
        END IF
    END IF
    ERROR 118
END SUB

SUB SetTime
    Out2 = MID$(Out2, 6)
    Out2 = STRIM$(Out2)
    IF LEFT$(Out2, 1) = "=" THEN
        Out2 = MID$(Out2, 2)
        Out2 = STRIM$(Out2)
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp3#)
        IF LastToken = False THEN
            TIME$ = Out3
            EXIT SUB
        END IF
    END IF
    ERROR 119
END SUB

SUB SetEnviron
    Out2 = MID$(Out2, 8)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    IF LastToken = False THEN
        ENVIRON Out3
        EXIT SUB
    END IF
    ERROR 165
END SUB

SUB SwapData
    Temp1$ = MID$(Out2, 5)
    Temp1$ = STRIM$(Temp1$)
    Temp2$ = UCASE$(LEFT$(Temp1$, 1))
    IF Temp2$ >= "A" AND Temp2$ <= "Z" THEN
        Variable1 = ASC(Temp2$) - 64
        Temp1$ = MID$(Temp1$, 2)
        Temp1$ = STRIM$(Temp1$)
        IF LEFT$(Temp1$, 1) = "," THEN
            Temp1$ = MID$(Temp1$, 2)
            Temp1$ = STRIM$(Temp1$)
            Temp2$ = UCASE$(LEFT$(Temp1$, 1))
            IF Temp2$ >= "A" AND Temp2$ <= "Z" THEN
                Variable2 = ASC(Temp2$) - 64
                Temp1$ = MID$(Temp1$, 2)
                Temp1$ = STRIM$(Temp1$)
                IF Temp1$ = Nul THEN
                    SWAP Variables(Variable1), Variables(Variable2)
                    EXIT SUB
                ELSE
                    IF LEFT$(Temp1$, 1) = "(" THEN
                        Out2 = MID$(Temp1$, 2)
                        Out2 = STRIM$(Out2)
                        LastToken = False
                        TokenIndex = 1
                        CALL GetToken
                        CALL Parse1(Temp3#)
                        Element = CINT(Temp3#)
                        IF Element > False AND Element <= MaxArrays THEN
                            SWAP Variables(Variable1), Arrays(Variable2, Element)
                            EXIT SUB
                        END IF
                    END IF
                END IF
            END IF
        ELSE
            IF LEFT$(Temp1$, 1) = "(" THEN
                Out2 = MID$(Temp1$, 2)
                Out2 = STRIM$(Out2)
                LastToken = False
                TokenIndex = 1
                CALL GetToken
                CALL Parse1(Temp3#)
                Element1 = CINT(Temp3#)
                Temp1$ = MID$(Out2, TokenIndex)
                Temp1$ = STRIM$(Temp1$)
                IF LEFT$(Temp1$, 1) = "," THEN
                    Out2 = MID$(Temp1$, 2)
                    Out2 = UCASE$(Out2)
                    Temp1$ = MID$(Temp1$, 2)
                    Temp1$ = STRIM$(Temp1$)
                    Temp2$ = UCASE$(LEFT$(Temp1$, 1))
                    IF Temp2$ >= "A" AND Temp2$ <= "Z" THEN
                        Variable2 = ASC(Temp2$) - 64
                        Temp1$ = MID$(Temp1$, 2)
                        Temp1$ = STRIM$(Temp1$)
                        IF Temp1$ = Nul THEN
                            IF Element1 > False AND Element1 <= MaxArrays THEN
                                SWAP Arrays(Variable1, Element1), Variables(Variable2)
                                EXIT SUB
                            END IF
                        ELSE
                            IF LEFT$(Temp1$, 1) = "(" THEN
                                Out2 = MID$(Temp1$, 2)
                                Out2 = STRIM$(Out2)
                                LastToken = False
                                TokenIndex = 1
                                CALL GetToken
                                CALL Parse1(Temp3#)
                                Element2 = CINT(Temp3#)
                                IF Element1 > False AND Element1 <= MaxArrays THEN
                                    IF Element2 > False AND Element2 <= MaxArrays THEN
                                        SWAP Arrays(Variable1, Element1), Arrays(Variable2, Element2)
                                        EXIT SUB
                                    END IF
                                END IF
                            END IF
                        END IF
                    END IF
                END IF
            ELSE
                IF LEFT$(Temp1$, 1) = "$" THEN
                    Temp1$ = MID$(Temp1$, 2)
                    Temp1$ = STRIM$(Temp1$)
                    IF LEFT$(Temp1$, 1) = "," THEN
                        Temp1$ = MID$(Temp1$, 2)
                        Temp1$ = STRIM$(Temp1$)
                        Temp2$ = UCASE$(LEFT$(Temp1$, 1))
                        IF Temp2$ >= "A" AND Temp2$ <= "Z" THEN
                            Variable2 = ASC(Temp2$) - 64
                            Temp1$ = MID$(Temp1$, 2)
                            Temp1$ = STRIM$(Temp1$)
                            IF Temp1$ = "$" THEN
                                SWAP Strngs$(Variable1), Strngs$(Variable2)
                                EXIT SUB
                            END IF
                        END IF
                    END IF
                END IF
            END IF
        END IF
    END IF
    ERROR 110
END SUB

SUB SleepSecond
    Out2 = MID$(Out2, 6)
    Out2 = STRIM$(Out2)
    IF LEN(Out2) = False THEN
        Temp3# = 1#
    ELSE
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp3#)
    END IF
    SLEEP CSNG(Temp3#)
    X$ = INKEY$
END SUB

SUB PauseSecond
    Out2 = MID$(Out2, 6)
    Out2 = STRIM$(Out2)
    IF LEN(Out2) = False THEN
        Temp3# = 1#
    ELSE
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp3#)
    END IF
    PauseTime! = CSNG(Temp3#)
    TimeNow! = TIMER
    DO
        _LIMIT 50
        ' calculate time elapsed
        ElapsedTime! = TIMER - TimeNow!
        ' adjust for midnight
        IF ElapsedTime! < 0! THEN
            ElapsedTime! = ElapsedTime! + 86400!
        END IF
        ' compare time elapsed
        IF ElapsedTime! > PauseTime! THEN
            EXIT DO
        END IF
        X$ = INKEY$
    LOOP
    X$ = INKEY$
END SUB

SUB OutputPort
    Out2 = MID$(Out2, 4)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp4#)
    PortAddress = CINT(Temp4#)
    IF Strng = "," THEN
        CALL GetToken
        CALL Parse1(Temp4#)
        PortByte = CINT(Temp4#)
        OUT PortAddress, PortByte
        EXIT SUB
    END IF
    ERROR 121
END SUB

SUB WaitPort
    AllowExtra = True
    Out2 = MID$(Out2, 5)
    Out2 = STRIM$(Out2)
    IF LEN(Out2) THEN
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp4#)
        PortAddress = CINT(Temp4#)
        IF Strng = "," THEN
            CALL GetToken
            CALL Parse1(Temp4#)
            AndValue = CINT(Temp4#)
            XorValue = False
            IF Strng = "," THEN
                CALL GetToken
                CALL Parse1(Temp4#)
                XorValue = CINT(Temp4#)
            END IF
            WAIT PortAddress, AndValue, XorValue
            EXIT SUB
        END IF
    END IF
    ERROR 122
END SUB

SUB AbsoluteFunction
    Out2 = MID$(Out2, 9)
    Out2 = STRIM$(Out2)
    IF LEN(Out2) THEN
        TokenIndex = 1
        CALL GetToken3
        CALL GetToken
        CALL Parse1(Temp4#)
        CALL GetToken4
        CALL ABSOLUTE(CINT(Temp4#))
        EXIT SUB
    END IF
    ERROR 123
END SUB

SUB PokeValue
    Out2 = MID$(Out2, 5)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp4#)
    Poke.Address = CINT(Temp4#)
    IF Strng = "," THEN
        CALL GetToken
        CALL Parse1(Temp4#)
        Poke.Byte = CINT(Temp4#)
        POKE Poke.Address, Poke.Byte
        EXIT SUB
    END IF
    ERROR 124
END SUB

SUB Int86Function
    Out2 = MID$(Out2, 6)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken3
    CALL GetToken
    CALL Parse1(Temp4#)
    CALL GetToken4
    Int86Value = CINT(Temp4#)
    IF Int86Value = &H33 THEN ' mouse
        InregsX.AX = INT(VAL("&H" + HEX$(AX)))
        InregsX.BX = INT(VAL("&H" + HEX$(BX)))
        InregsX.CX = INT(VAL("&H" + HEX$(CX)))
        InregsX.DX = INT(VAL("&H" + HEX$(DX)))
        InregsX.BP = INT(VAL("&H" + HEX$(BP)))
        InregsX.SI = INT(VAL("&H" + HEX$(SI)))
        InregsX.DI = INT(VAL("&H" + HEX$(DI)))
        InregsX.FL = INT(VAL("&H" + HEX$(FL)))
        InregsX.DS = INT(VAL("&H" + HEX$(DS)))
        InregsX.ES = INT(VAL("&H" + HEX$(ES)))
        CALL INTERRUPTX(Int86Value, InregsX, OutregsX)
        IF OutregsX.AX < False THEN
            AX = CDBL(OutregsX.AX + 65536)
        ELSE
            AX = CDBL(OutregsX.AX)
        END IF
        IF OutregsX.BX < False THEN
            BX = CDBL(OutregsX.BX + 65536)
        ELSE
            BX = CDBL(OutregsX.BX)
        END IF
        IF OutregsX.CX < False THEN
            CX = CDBL(OutregsX.CX + 65536)
        ELSE
            CX = CDBL(OutregsX.CX)
        END IF
        IF OutregsX.DX < False THEN
            DX = CDBL(OutregsX.DX + 65536)
        ELSE
            DX = CDBL(OutregsX.DX)
        END IF
        IF OutregsX.BP < False THEN
            BP = CDBL(OutregsX.BP + 65536)
        ELSE
            BP = CDBL(OutregsX.BP)
        END IF
        IF OutregsX.SI < False THEN
            SI = CDBL(OutregsX.SI + 65536)
        ELSE
            SI = CDBL(OutregsX.SI)
        END IF
        IF OutregsX.DI < False THEN
            DI = CDBL(OutregsX.DI + 65536)
        ELSE
            DI = CDBL(OutregsX.DI)
        END IF
        IF OutregsX.FL < False THEN
            FL = CDBL(OutregsX.FL + 65536)
        ELSE
            FL = CDBL(OutregsX.FL)
        END IF
        IF OutregsX.DS < False THEN
            DS = CDBL(OutregsX.DS + 65536)
        ELSE
            DS = CDBL(OutregsX.DS)
        END IF
        IF OutregsX.ES < False THEN
            ES = CDBL(OutregsX.ES + 65536)
        ELSE
            ES = CDBL(OutregsX.ES)
        END IF
    ELSE
        ERROR 158
    END IF
END SUB

SUB DefsegFunction
    Out2 = MID$(Out2, 7)
    Out2 = STRIM$(Out2)
    IF LEN(Out2) = False THEN
        DEF SEG ' restore segment
        InDEFSEG = False ' reset segment flag
        EXIT SUB
    END IF
    TokenIndex = 1
    CALL GetToken3
    CALL GetToken
    CALL Parse1(Temp4#)
    CALL GetToken4
    IF Temp4# >= 0# AND Temp4# <= 65535# THEN
        DEF SEG = Temp4# ' set segment
        InDEFSEG = True ' set segment flag
        DEFSEGvalue = Temp4# ' store segment value
        EXIT SUB
    END IF
    ERROR 125
END SUB

SUB SeedRandom
    Out2 = MID$(Out2, 10)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken
    CALL Parse1(Temp3#)
    RANDOMIZE CLNG(Temp3#)
END SUB

' def fn(x)=value
SUB DefineFunction
    Out2 = MID$(Out2, 7)
    Out2 = STRIM$(Out2)
    TokenIndex = 1
    CALL GetToken3
    CALL GetToken
    CALL Parse1(Temp4#)
    CALL GetToken4
    Func% = CINT(Temp4#)
    IF Func% >= 1 AND Func% <= MaxFunctions THEN
        Out2 = MID$(Out2, TokenIndex)
        Out2 = LTRIM$(Out2)
        IF LEFT$(Out2, 1) = "=" THEN
            Out2 = MID$(Out2, 2)
            Definitions$(Func%) = Out2
            EXIT SUB
        END IF
    END IF
    ERROR 144
END SUB

' accepts an operation and performs on two values, string or numeric
SUB Arith (TokenParsed$, Temp#, Temp2#)
    IF LastToken THEN
        SELECT CASE TokenParsed$
            CASE "-"
                Temp# = Temp# - Temp2#
            CASE "+"
                Temp# = Temp# + Temp2#
            CASE "/"
                Temp# = Temp# / Temp2#
            CASE "\"
                Temp# = Temp# \ Temp2#
            CASE "*"
                Temp# = Temp# * Temp2#
            CASE "^"
                Temp# = Temp# ^ Temp2#
            CASE "<"
                Temp# = (Temp# < Temp2#)
            CASE ">"
                Temp# = (Temp# > Temp2#)
            CASE "<<"
                Temp# = Temp# * 2#
            CASE ">>"
                Temp# = Temp# \ 2#
            CASE "||"
                Temp# = Temp# * 10#
            CASE "##"
                Temp# = Temp# \ 10#
            CASE "^^"
                Temp# = Temp# ^ 10#
            CASE "++"
                Temp# = Temp# + 1#
            CASE "--"
                Temp# = Temp# - 1#
            CASE "**"
                Temp# = Temp# ^ 2#
            CASE "//"
                Temp# = SQR(Temp#)
            CASE "="
                Temp# = (Temp# = Temp2#)
            CASE "<="
                Temp# = (Temp# <= Temp2#)
            CASE ">="
                Temp# = (Temp# >= Temp2#)
            CASE "<>"
                Temp# = (Temp# <> Temp2#)
            CASE "=="
                CaseValue1 = Temp#
                CaseValue2 = Temp2#
                LastToken = 2
            CASE "|"
                Temp# = Temp# OR Temp2#
            CASE "&"
                Temp# = Temp# AND Temp2#
            CASE "%"
                Temp# = Temp# MOD Temp2#
            CASE "~"
                Temp# = Temp# XOR Temp2#
            CASE "?"
                Temp# = Temp# IMP Temp2#
            CASE ":"
                Temp# = Temp# EQV Temp2#
            CASE "#"
                Temp# = NOT (Temp# OR Temp2#)
            CASE "@"
                Temp# = NOT (Temp# IMP Temp2#)
            CASE "`"
                Temp# = NOT (Temp# AND Temp2#)
        END SELECT
        EXIT SUB
    END IF
    SELECT CASE TokenParsed$
        CASE "-"
            IF RIGHT$(Out3, LEN(Out4)) = Out4 THEN
                Out3 = LEFT$(Out3, LEN(Out3) - LEN(Out4))
            END IF
        CASE "+"
            Out3 = Out3 + Out4
        CASE "/", "\"
            IF LEN(Out3) > False AND LEN(Out4) > False THEN
                Imbedded = INSTR(Out3, Out4)
                WHILE Imbedded
                    Out3 = LEFT$(Out3, Imbedded - 1) + MID$(Out3, Imbedded + LEN(Out4))
                    Imbedded = INSTR(Out3, Out4)
                WEND
            END IF
        CASE "<"
            LastToken = True
            Temp# = Out3 < Out4
        CASE ">"
            LastToken = True
            Temp# = Out3 > Out4
        CASE "="
            LastToken = True
            Temp# = Out3 = Out4
        CASE "<="
            LastToken = True
            Temp# = Out3 <= Out4
        CASE ">="
            LastToken = True
            Temp# = Out3 >= Out4
        CASE "<>"
            LastToken = True
            Temp# = Out3 <> Out4
        CASE "=="
            CaseValueS1 = Out3
            CaseValueS2 = Out4
            LastToken = 2
    END SELECT
END SUB

' accepts an operation and performs on one numeric variable
SUB Assignment1 (TempS$, TempS3%)
    IF TempS$ = "<<" THEN
        Assign = True
        Strng = Nul
        Variables(TempS3%) = Variables(TempS3%) * 2#
        EXIT SUB
    END IF
    IF TempS$ = ">>" THEN
        Assign = True
        Strng = Nul
        Variables(TempS3%) = Variables(TempS3%) / 2#
        EXIT SUB
    END IF
    IF TempS$ = "||" THEN
        Assign = True
        Strng = Nul
        Variables(TempS3%) = Variables(TempS3%) * 10#
        EXIT SUB
    END IF
    IF TempS$ = "##" THEN
        Assign = True
        Strng = Nul
        Variables(TempS3%) = Variables(TempS3%) / 10#
        EXIT SUB
    END IF
    IF TempS$ = "^^" THEN
        Assign = True
        Strng = Nul
        Variables(TempS3%) = Variables(TempS3%) ^ 10#
        EXIT SUB
    END IF
    IF TempS$ = "--" THEN
        Assign = True
        Strng = Nul
        Variables(TempS3%) = Variables(TempS3%) - 1#
        EXIT SUB
    END IF
    IF TempS$ = "++" THEN
        Assign = True
        Strng = Nul
        Variables(TempS3%) = Variables(TempS3%) + 1#
        EXIT SUB
    END IF
    IF TempS$ = "**" THEN
        Assign = True
        Strng = Nul
        Variables(TempS3%) = Variables(TempS3%) ^ 2#
        EXIT SUB
    END IF
    IF TempS$ = "//" THEN
        Assign = True
        Strng = Nul
        Variables(TempS3%) = SQR(Variables(TempS3%))
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "-=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        CALL Equate(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Variables(TempS3%) = Variables(TempS3%) - Temp4#
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "+=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        CALL Equate(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Variables(TempS3%) = Variables(TempS3%) + Temp4#
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "/=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        CALL Equate(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Variables(TempS3%) = Variables(TempS3%) / Temp4#
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "\=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        CALL Equate(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Variables(TempS3%) = Variables(TempS3%) \ Temp4#
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "*=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        CALL Equate(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Variables(TempS3%) = Variables(TempS3%) * Temp4#
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "^=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        CALL Equate(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Variables(TempS3%) = Variables(TempS3%) ^ Temp4#
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 3) = "^-=" THEN
        Out2 = MID$(TempS$, 4)
        Out2 = STRIM$(Out2)
        CALL Equate(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Variables(TempS3%) = Variables(TempS3%) ^ (-Temp4#)
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "%=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        CALL Equate(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Variables(TempS3%) = Variables(TempS3%) MOD Temp4#
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "|=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        CALL Equate(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Variables(TempS3%) = Variables(TempS3%) OR Temp4#
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "&=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        CALL Equate(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Variables(TempS3%) = Variables(TempS3%) AND Temp4#
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "~=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        CALL Equate(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Variables(TempS3%) = Variables(TempS3%) XOR Temp4#
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "?=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        CALL Equate(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Variables(TempS3%) = Variables(TempS3%) IMP Temp4#
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = ":=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        CALL Equate(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Variables(TempS3%) = Variables(TempS3%) EQV Temp4#
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "#=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        CALL Equate(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Variables(TempS3%) = NOT (Variables(TempS3%) OR Temp4#)
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "@=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        CALL Equate(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Variables(TempS3%) = NOT (Variables(TempS3%) IMP Temp4#)
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "`=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        CALL Equate(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Variables(TempS3%) = NOT (Variables(TempS3%) AND Temp4#)
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 1) = "=" THEN
        Out2 = MID$(TempS$, 2)
        Out2 = STRIM$(Out2)
        CALL Equate(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Variables(TempS3%) = Temp4#
        END IF
        EXIT SUB
    END IF
END SUB

' accepts an operation and performs on one numeric array element
SUB Assignment2 (TempS$, TempS1%, TempS2%)
    IF TempS$ = "<<" THEN
        Assign = True
        Strng = Nul
        Arrays(TempS1%, TempS2%) = Arrays(TempS1%, TempS2%) * 2#
        EXIT SUB
    END IF
    IF TempS$ = ">>" THEN
        Assign = True
        Strng = Nul
        Arrays(TempS1%, TempS2%) = Arrays(TempS1%, TempS2%) / 2#
        EXIT SUB
    END IF
    IF TempS$ = "||" THEN
        Assign = True
        Strng = Nul
        Arrays(TempS1%, TempS2%) = Arrays(TempS1%, TempS2%) * 10#
        EXIT SUB
    END IF
    IF TempS$ = "##" THEN
        Assign = True
        Strng = Nul
        Arrays(TempS1%, TempS2%) = Arrays(TempS1%, TempS2%) / 10#
        EXIT SUB
    END IF
    IF TempS$ = "^^" THEN
        Assign = True
        Strng = Nul
        Arrays(TempS1%, TempS2%) = Arrays(TempS1%, TempS2%) ^ 10#
        EXIT SUB
    END IF
    IF TempS$ = "--" THEN
        Assign = True
        Strng = Nul
        Arrays(TempS1%, TempS2%) = Arrays(TempS1%, TempS2%) - 1#
        EXIT SUB
    END IF
    IF TempS$ = "++" THEN
        Assign = True
        Strng = Nul
        Arrays(TempS1%, TempS2%) = Arrays(TempS1%, TempS2%) + 1#
        EXIT SUB
    END IF
    IF TempS$ = "**" THEN
        Assign = True
        Strng = Nul
        Arrays(TempS1%, TempS2%) = Arrays(TempS1%, TempS2%) ^ 2#
        EXIT SUB
    END IF
    IF TempS$ = "//" THEN
        Assign = True
        Strng = Nul
        Arrays(TempS1%, TempS2%) = SQR(Arrays(TempS1%, TempS2%))
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "-=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Arrays(TempS1%, TempS2%) = Arrays(TempS1%, TempS2%) - Temp4#
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "+=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Arrays(TempS1%, TempS2%) = Arrays(TempS1%, TempS2%) + Temp4#
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "/=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Arrays(TempS1%, TempS2%) = Arrays(TempS1%, TempS2%) / Temp4#
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "\=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Arrays(TempS1%, TempS2%) = Arrays(TempS1%, TempS2%) \ Temp4#
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "*=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Arrays(TempS1%, TempS2%) = Arrays(TempS1%, TempS2%) * Temp4#
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "^=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Arrays(TempS1%, TempS2%) = Arrays(TempS1%, TempS2%) ^ Temp4#
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 3) = "^-=" THEN
        Out2 = MID$(TempS$, 4)
        Out2 = STRIM$(Out2)
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Arrays(TempS1%, TempS2%) = Arrays(TempS1%, TempS2%) ^ (-Temp4#)
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "%=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Arrays(TempS1%, TempS2%) = Arrays(TempS1%, TempS2%) MOD Temp4#
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "|=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Arrays(TempS1%, TempS2%) = Arrays(TempS1%, TempS2%) OR Temp4#
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "&=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Arrays(TempS1%, TempS2%) = Arrays(TempS1%, TempS2%) AND Temp4#
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "~=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Arrays(TempS1%, TempS2%) = Arrays(TempS1%, TempS2%) XOR Temp4#
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "?=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Arrays(TempS1%, TempS2%) = Arrays(TempS1%, TempS2%) IMP Temp4#
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = ":=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Arrays(TempS1%, TempS2%) = Arrays(TempS1%, TempS2%) EQV Temp4#
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "#=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Arrays(TempS1%, TempS2%) = NOT (Arrays(TempS1%, TempS2%) OR Temp4#)
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "@=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Arrays(TempS1%, TempS2%) = NOT (Arrays(TempS1%, TempS2%) IMP Temp4#)
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 2) = "`=" THEN
        Out2 = MID$(TempS$, 3)
        Out2 = STRIM$(Out2)
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Arrays(TempS1%, TempS2%) = NOT (Arrays(TempS1%, TempS2%) AND Temp4#)
        END IF
        EXIT SUB
    END IF
    IF LEFT$(TempS$, 1) = "=" THEN
        Out2 = MID$(TempS$, 2)
        Out2 = STRIM$(Out2)
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp4#)
        IF LastToken = True THEN
            Assign = True
            Arrays(TempS1%, TempS2%) = Temp4#
        END IF
    END IF
END SUB

' gets a value and assigns to one register variable
SUB Assignment3 (TempS1$, TempS2$)
    SELECT CASE TempS2$
        CASE "AX"
            Out2 = TempS1$
            CALL Equate(Temp4#)
            IF LastToken = True THEN
                Assign = True
                AX = Temp4#
            END IF
            EXIT SUB
        CASE "BX"
            Out2 = TempS1$
            CALL Equate(Temp4#)
            IF LastToken = True THEN
                Assign = True
                BX = Temp4#
            END IF
            EXIT SUB
        CASE "CX"
            Out2 = TempS1$
            CALL Equate(Temp4#)
            IF LastToken = True THEN
                Assign = True
                CX = Temp4#
            END IF
            EXIT SUB
        CASE "DX"
            Out2 = TempS1$
            CALL Equate(Temp4#)
            IF LastToken = True THEN
                Assign = True
                DX = Temp4#
            END IF
            EXIT SUB
        CASE "BP"
            Out2 = TempS1$
            CALL Equate(Temp4#)
            IF LastToken = True THEN
                Assign = True
                BP = Temp4#
            END IF
            EXIT SUB
        CASE "SI"
            Out2 = TempS1$
            CALL Equate(Temp4#)
            IF LastToken = True THEN
                Assign = True
                SI = Temp4#
            END IF
            EXIT SUB
        CASE "DI"
            Out2 = TempS1$
            CALL Equate(Temp4#)
            IF LastToken = True THEN
                Assign = True
                DI = Temp4#
            END IF
            EXIT SUB
        CASE "FL"
            Out2 = TempS1$
            CALL Equate(Temp4#)
            IF LastToken = True THEN
                Assign = True
                FL = Temp4#
            END IF
            EXIT SUB
        CASE "DS"
            Out2 = TempS1$
            CALL Equate(Temp4#)
            IF LastToken = True THEN
                Assign = True
                DS = Temp4#
            END IF
            EXIT SUB
        CASE "ES"
            Out2 = TempS1$
            CALL Equate(Temp4#)
            IF LastToken = True THEN
                Assign = True
                ES = Temp4#
            END IF
            EXIT SUB
    END SELECT
END SUB

' gets a value and assigns to one error variable
SUB Assignment4 (TempS1$, TempS2$)
    SELECT CASE TempS2$
        CASE "ERR"
            Out2 = TempS1$
            CALL Equate(Temp4#)
            IF LastToken = True THEN
                Assign = True
                ErrorValue = CINT(Temp4#)
                ErrorValue2 = CINT(Temp4#)
            END IF
            EXIT SUB
        CASE "ERL"
            Out2 = TempS1$
            CALL Equate(Temp4#)
            IF LastToken = True THEN
                Assign = True
                ErrorLine = CINT(Temp4#)
            END IF
            EXIT SUB
    END SELECT
END SUB

' entry to expression parser,
' each following parser is higher precedence,
' this routine called by higher precedence routines recursively.

REM precedence of operators (from highest to lowest):
REM   !, +, - Not, Unary plus, Unary Minus
REM   ^       Power
REM   *, /    Multiplication, Division
REM   \       Integer division
REM   %       Modulo
REM   +, -    Addition, Subtraction
REM   =, <, >, <>, >=, <= Relational
REM   |, &, ~, ?, :, #, @, ` Logical (or, and, xor, imp, eqv, nor, non, xan)

REM  Returns LastToken equal to:
REM    0  =  string
REM   -1  =  numeric
REM    1  =  token IS/ISNT
REM    2  =  token is ==
REM    3  =  token , or ;

SUB Equate (Temp#)
    LastToken = False
    Out3 = Nul ' reset string storage
    Out4 = Nul ' reset string concatenate storage
    Temp# = Dfalse ' reset result
    TokenIndex = 1 ' reset pointer to expression token
    CALL GetToken ' read next token
    CALL Parse1(Temp#) ' entry to parse the expression
    ' parse leftover tokens
    WHILE LEN(Strng)
        CALL Parse1(X#)
        ' toss away any unwanted tokens
        IF LastToken = 3 THEN
            IF AllowExtra = False THEN
                Strng = "<extra token>"
                ERROR 92
            END IF
        END IF
    WEND
END SUB

' verifies next token is opening parenthesis.
SUB GetToken3
    Strng = Nul
    Token = False
    IF MID$(Out2, TokenIndex, 1) = " " THEN
        TokenIndex = TokenIndex + 1
    END IF
    IF TokenIndex > LEN(Out2) THEN
        ERROR 138
    END IF
    ' locate parenthesis symbol
    TokenElement$ = MID$(Out2, TokenIndex, 1)
    IF TokenElement$ = "(" THEN
        Token = 1 ' store token type
        Strng = TokenElement$ ' store token
        TokenIndex = TokenIndex + 1 ' increment pointer
        EXIT SUB
    END IF
    ERROR 138
END SUB

' verifies last token is closing parenthesis.
SUB GetToken4
    ' locate parenthesis symbol
    IF Strng = ")" THEN
        EXIT SUB
    END IF
    ERROR 139
END SUB

' returns next token in string form,
' increments pointer to next token,
' determines token type.
SUB GetToken
    Strng = Nul
    Token = False
    IF MID$(Out2, TokenIndex, 1) = " " THEN
        TokenIndex = TokenIndex + 1
    END IF
    CALL GetToken2(TokenExists)
    IF TokenExists THEN
        EXIT SUB
    END IF
    IF TokenIndex > LEN(Out2) THEN
        Strng = Nul
        Token = False
        TokenIndex = TokenIndex + 1
        EXIT SUB
    END IF
    ' locate expression symbol
    TokenElement$ = MID$(Out2, TokenIndex, 1)
    IF INSTR(TokenList, TokenElement$) THEN
        Token = 1 ' store token type
        Strng = TokenElement$ ' store token
        TokenIndex = TokenIndex + 1 ' increment pointer
        EXIT SUB
    END IF
    ' locate expression is number
    TokenElement$ = MID$(Out2, TokenIndex, 1)
    IF TokenElement$ >= "0" AND TokenElement$ <= "9" THEN
        ' increment token until token is other than number
        DO
            IF LEN(TokenElement$) = False THEN
                EXIT DO
            END IF
            IF INSTR(TokenList, TokenElement$) THEN
                EXIT DO
            END IF
            Strng = Strng + TokenElement$
            TokenIndex = TokenIndex + 1
            TokenElement$ = MID$(Out2, TokenIndex, 1)
        LOOP
        Token = 2 ' store token type
        EXIT SUB
    END IF
    ' locate expression is number beginning with decimal
    TokenElement$ = MID$(Out2, TokenIndex, 1)
    IF TokenElement$ = "." THEN
        ' increment token until token is other than number
        DO
            IF LEN(TokenElement$) = False THEN
                EXIT DO
            END IF
            IF INSTR(TokenList, TokenElement$) THEN
                EXIT DO
            END IF
            Strng = Strng + TokenElement$
            TokenIndex = TokenIndex + 1
            TokenElement$ = MID$(Out2, TokenIndex, 1)
        LOOP
        Token = 2 ' store token type
        EXIT SUB
    END IF
    ' locate expression is alphabetic
    TokenElement$ = UCASE$(MID$(Out2, TokenIndex, 1))
    IF TokenElement$ >= "A" AND TokenElement$ <= "Z" THEN
        ' increment token until token is other than alphabetic
        DO
            IF LEN(TokenElement$) = False THEN
                EXIT DO
            END IF
            IF INSTR(TokenList, TokenElement$) THEN
                EXIT DO
            END IF
            Strng = Strng + TokenElement$
            TokenIndex = TokenIndex + 1
            TokenElement$ = UCASE$(MID$(Out2, TokenIndex, 1))
        LOOP
        Token = 3 ' store token type
        EXIT SUB
    END IF
    ' store unknown token
    Token = False
    Strng = TokenElement$
    TokenIndex = TokenIndex + 1
END SUB

' returns next two-character token in string form,
' increments pointer to next token,
' determines token type.
SUB GetToken2 (TokenExists)
    TokenExists = False
    StoredToken$ = Out2
    IF MID$(StoredToken$, TokenIndex + 1, 1) = " " THEN
        StoredToken$ = LEFT$(StoredToken$, TokenIndex) + MID$(StoredToken$, TokenIndex + 2)
    END IF
    ' locate expression symbols
    NextToken$ = MID$(StoredToken$, TokenIndex, 2)
    SELECT CASE NextToken$
        CASE "<<"
            GOSUB RemoveSpaces
            Token = 1 ' store token type
            Strng = "<<" ' store token
            TokenIndex = TokenIndex + 2 ' increment pointer
            TokenExists = True
        CASE ">>"
            GOSUB RemoveSpaces
            Token = 1 ' store token type
            Strng = ">>" ' store token
            TokenIndex = TokenIndex + 2 ' increment pointer
            TokenExists = True
        CASE "||"
            GOSUB RemoveSpaces
            Token = 1 ' store token type
            Strng = "||" ' store token
            TokenIndex = TokenIndex + 2 ' increment pointer
            TokenExists = True
        CASE "##"
            GOSUB RemoveSpaces
            Token = 1 ' store token type
            Strng = "##" ' store token
            TokenIndex = TokenIndex + 2 ' increment pointer
            TokenExists = True
        CASE "^^"
            GOSUB RemoveSpaces
            Token = 1 ' store token type
            Strng = "^^" ' store token
            TokenIndex = TokenIndex + 2 ' increment pointer
            TokenExists = True
        CASE "--"
            GOSUB RemoveSpaces
            Token = 1 ' store token type
            Strng = "--" ' store token
            TokenIndex = TokenIndex + 2 ' increment pointer
            TokenExists = True
        CASE "++"
            GOSUB RemoveSpaces
            Token = 1 ' store token type
            Strng = "++" ' store token
            TokenIndex = TokenIndex + 2 ' increment pointer
            TokenExists = True
        CASE "**"
            GOSUB RemoveSpaces
            Token = 1 ' store token type
            Strng = "**" ' store token
            TokenIndex = TokenIndex + 2 ' increment pointer
            TokenExists = True
        CASE "//"
            GOSUB RemoveSpaces
            Token = 1 ' store token type
            Strng = "//" ' store token
            TokenIndex = TokenIndex + 2 ' increment pointer
            TokenExists = True
        CASE ">=", "=>"
            GOSUB RemoveSpaces
            Token = 1 ' store token type
            Strng = ">=" ' store token
            TokenIndex = TokenIndex + 2 ' increment pointer
            TokenExists = True
        CASE "<=", "=<"
            GOSUB RemoveSpaces
            Token = 1 ' store token type
            Strng = "<=" ' store token
            TokenIndex = TokenIndex + 2 ' increment pointer
            TokenExists = True
        CASE "<>", "><"
            GOSUB RemoveSpaces
            Token = 1 ' store token type
            Strng = "<>" ' store token
            TokenIndex = TokenIndex + 2 ' increment pointer
            TokenExists = True
        CASE "=="
            GOSUB RemoveSpaces
            Token = 1 ' store token type
            Strng = "==" ' store token
            TokenIndex = TokenIndex + 2 ' increment pointer
            TokenExists = True
    END SELECT
    EXIT SUB

    ' locate and remove spaces
    RemoveSpaces:
    IF MID$(Out2, TokenIndex + 1, 1) = " " THEN
        Out2 = LEFT$(Out2, TokenIndex) + MID$(Out2, TokenIndex + 2)
    END IF
    RETURN
END SUB

' parses out single variable tokens
SUB ParseAlphabetic1 (Temp#)
    SELECT CASE UCASE$(Strng) ' test variable symbol
        CASE "A" TO "Z"
            Element = ASC(UCASE$(Strng)) - 64
            ElementType$ = MID$(Out2, TokenIndex, 1)
            SELECT CASE ElementType$
                CASE "("
                    CALL GetToken
                    CALL GetToken
                    CALL Parse1(Temp#)
                    IF Strng = ")" THEN
                        Temp# = Arrays(Element, CINT(Temp#))
                        LastToken = True
                    ELSE
                        Strng = "<missing closing token>"
                        ERROR 92
                    END IF
                CASE "["
                    CALL GetToken
                    CALL GetToken
                    CALL Parse1(Temp#)
                    IF Strng = "]" THEN
                        Temp# = Arrays(Element, CINT(Temp#))
                        LastToken = True
                    ELSE
                        Strng = "<missing closing token>"
                        ERROR 92
                    END IF
                CASE "{"
                    CALL GetToken
                    CALL GetToken
                    CALL Parse1(Temp#)
                    IF Strng = "}" THEN
                        Temp# = Arrays(Element, CINT(Temp#))
                        LastToken = True
                    ELSE
                        Strng = "<missing closing token>"
                        ERROR 92
                    END IF
                CASE ELSE
                    Temp# = Variables(Element)
                    LastToken = True
            END SELECT
        CASE ELSE
            IF AllowAlpha THEN
                Out3 = Strng
            ELSE
                Strng = "(" + Strng + ")"
                ERROR 92
            END IF
    END SELECT
END SUB

' parses out two-letter variable tokens
SUB ParseAlphabetic2 (Temp#)
    SELECT CASE UCASE$(Strng)
        ' user defined functions
        CASE "FN"
            CALL ParseFN(Temp#)
        CASE "FZ"
            CALL ParseFZ(Temp#)
            ' interrupt functions
        CASE "AX"
            Temp# = AX
            LastToken = True
        CASE "BX"
            Temp# = BX
            LastToken = True
        CASE "CX"
            Temp# = CX
            LastToken = True
        CASE "DX"
            Temp# = DX
            LastToken = True
        CASE "BP"
            Temp# = BP
            LastToken = True
        CASE "SI"
            Temp# = SI
            LastToken = True
        CASE "DI"
            Temp# = DI
            LastToken = True
        CASE "FL"
            Temp# = FL
            LastToken = True
        CASE "DS"
            Temp# = DS
            LastToken = True
        CASE "ES"
            Temp# = ES
            LastToken = True
            ' functions w/o parameters
        CASE "PI" ' calculate PI
            Temp# = ATN(1#) * 4#
            LastToken = True
        CASE "EX" ' calculate E
            Temp# = EXP(1#)
            LastToken = True
            ' special case functions
        CASE "IS"
            CALL GetToken
            Strng2$ = Strng
            CALL GetToken
            CALL Parse1(Temp4#)
            Out4 = Out3
            Temp3# = CaseValue
            Out3 = CaseStrng
            Strng = Strng2$
            CALL Arith(Strng, Temp3#, Temp4#)
            ValueIs = Temp3#
            LastToken = 1
        CASE "OR"
            CALL GetToken
            CALL GetToken
            CALL Parse1(Temp#)
            Number# = Temp#
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = Number# OR Temp#
            LastToken = True
            ' special case constants
        CASE "CR"
            Out3 = CHR$(13)
            LastToken = False
        CASE "LF"
            Out3 = CHR$(10)
            LastToken = False
        CASE ELSE
            IF MID$(Strng, 2, 1) = "$" THEN
                SELECT CASE MID$(Out2, TokenIndex, 1)
                    CASE "(", "[", "{"
                        Strng = "<bad string token>"
                        ERROR 92
                END SELECT
                SELECT CASE UCASE$(LEFT$(Strng, 1))
                    CASE "A" TO "Z"
                        Element = ASC(UCASE$(LEFT$(Strng, 1))) - 64
                        Out3 = Strngs$(Element)
                        LastToken = False
                END SELECT
            ELSE
                IF AllowAlpha THEN
                    Out3 = Strng
                ELSE
                    Strng = "[" + Strng + "]"
                    ERROR 92
                END IF
            END IF
    END SELECT
END SUB

' parses FN(<x>)
SUB ParseFN (Temp#)
    Var$ = LEFT$(Out2, TokenIndex - 3)
    CALL GetToken3
    CALL GetToken
    CALL Parse1(Temp4#)
    CALL GetToken4
    Func% = CINT(Temp4#)
    IF Func% >= 1 AND Func% <= MaxFunctions THEN
        Var2$ = MID$(Out2, TokenIndex)
        Out2 = Definitions$(Func%)
        Out2 = STRIM$(Out2)
        ' test for nul token
        IF Out2 = Nul THEN
            Strng = "<bad FN token>"
            ERROR 148
            EXIT SUB
        END IF
        ' count recursing calls
        Recurse = Recurse + 1
        IF Recurse > MaxRecurse THEN
            Strng = "<bad FN recurse>"
            ERROR 148
            EXIT SUB
        END IF
        ' recursively call functions
        TokenIndex = 1
        CALL GetToken
        CALL Parse1(Temp#)
        ' test huge recursed FN
        IF LEN(Var$) + LEN(Var2$) >= MaxFNlength THEN
            Var$ = Nul
            Var2$ = Nul
            Strng = "<bad FN string>"
            ERROR 148
            EXIT SUB
        END IF
        ' re-concatenate equation
        Out2 = Var$ + Var2$
        TokenIndex = LEN(Var$) + 1
        EXIT SUB
    END IF
    Strng = "<bad FN range>"
    ERROR 148
END SUB

' parses FZ(<x>)
SUB ParseFZ (Temp#)
    CALL GetToken3
    CALL GetToken
    CALL Parse1(Temp4#)
    CALL GetToken4
    Func% = CINT(Temp4#)
    IF Func% >= 1 AND Func% <= MaxFunctions THEN
        Out3 = Definitions$(Func%)
        Out3 = STRIM$(Out3)
        IF Out3 = Nul THEN
            Strng = "<bad FN token>"
            ERROR 149
            EXIT SUB
        END IF
        LastToken = False
        EXIT SUB
    END IF
    Strng = "<bad FN range>"
    ERROR 149
END SUB

' parses out three-letter and greater variable tokens
SUB ParseAlphabetic3 (Temp#)
    SELECT CASE UCASE$(Strng)
        CASE "SXR"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Out3 = SxriptEval$(Out3)
            CALL GetToken4
            LastToken = False
            ' special purpose functions
        CASE "ISNT"
            CALL GetToken
            Strng2$ = Strng
            CALL GetToken
            CALL Parse1(Temp4#)
            Out4 = Out3
            Temp3# = CaseValue
            Out3 = CaseStrng
            Strng = Strng2$
            CALL Arith(Strng, Temp3#, Temp4#)
            ValueIs = NOT Temp3#
            LastToken = 1
        CASE "SCREEN"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Xcoor# = Temp#
            CALL GetToken
            CALL Parse1(Temp#)
            Ycoor# = Temp#
            Temp# = SCREEN(Xcoor#, Ycoor#)
            CALL GetToken4
            LastToken = True
        CASE "SCREENX"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Xcoor# = Temp#
            CALL GetToken
            CALL Parse1(Temp#)
            Ycoor# = Temp#
            Temp# = SCREEN(Xcoor#, Ycoor#, 1)
            CALL GetToken4
            LastToken = True
        CASE "POINT"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Xcoor# = Temp#
            CALL GetToken
            CALL Parse1(Temp#)
            Ycoor# = Temp#
            Temp# = POINT(Xcoor#, Ycoor#)
            CALL GetToken4
            LastToken = True
            ' functions w/o parameters
        CASE "CRLF"
            Out3 = CHR$(13) + CHR$(10)
            LastToken = False
        CASE "NUL", "NULL"
            Out3 = Nul
            LastToken = False
        CASE "FALSE"
            Temp# = Dfalse
            LastToken = True
        CASE "TRUE"
            Temp# = Dtrue
            LastToken = True
        CASE "QUOTE$"
            Out3 = CHR$(34)
            LastToken = False
        CASE "FREEFILE"
            FileNum% = FREEFILE
            IF FileNum% >= 1 AND FileNum% <= MaxFiles THEN
                Temp# = CDBL(FileNum%)
            ELSE
                Temp# = Dfalse
            END IF
            LastToken = True
        CASE "RND"
            Temp# = RND
            LastToken = True
        CASE "POS"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = POS(0)
            CALL GetToken4
            Out3 = Nul
            LastToken = True
        CASE "CSRLIN"
            Temp# = CSRLIN
            LastToken = True
        CASE "ERR"
            Temp# = CDBL(ErrorValue2)
            LastToken = True
        CASE "ERL"
            Temp# = CDBL(ErrorLine)
            LastToken = True
        CASE "ARRAYSIZE"
            Temp# = CDBL(ArraySize)
            LastToken = True
            ' boolean functions
        CASE "AND"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Number# = Temp#
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = Number# AND Temp#
            CALL GetToken4
            LastToken = True
        CASE "MOD"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Number# = Temp#
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = Number# MOD Temp#
            CALL GetToken4
            LastToken = True
        CASE "NOR"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Number# = Temp#
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = NOT (Number# OR Temp#)
            CALL GetToken4
            LastToken = True
        CASE "NON"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Number# = Temp#
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = NOT (Number# IMP Temp#)
            CALL GetToken4
            LastToken = True
        CASE "XAN"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Number# = Temp#
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = NOT (Number# AND Temp#)
            CALL GetToken4
            LastToken = True
        CASE "XOR"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Number# = Temp#
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = Number# XOR Temp#
            CALL GetToken4
            LastToken = True
        CASE "IMP"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Number# = Temp#
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = Number# IMP Temp#
            CALL GetToken4
            LastToken = True
        CASE "EQV"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Number# = Temp#
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = Number# EQV Temp#
            CALL GetToken4
            LastToken = True
        CASE "NOT"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = NOT Temp#
            CALL GetToken4
            LastToken = True
            ' third-order boolean
        CASE "TAND"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Number1# = Temp#
            CALL GetToken
            CALL Parse1(Temp#)
            Number2# = Temp#
            CALL GetToken4
            SELECT CASE Number1#
                CASE -1, 0, 1
                    SELECT CASE Number2#
                        CASE -1, 0, 1
                            Temp# = Number1# AND Number2#
                            LastToken = True
                            EXIT SUB
                    END SELECT
            END SELECT
            ERROR 2
        CASE "TOR"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Number1# = Temp#
            CALL GetToken
            CALL Parse1(Temp#)
            Number2# = Temp#
            CALL GetToken4
            SELECT CASE Number1#
                CASE -1, 0, 1
                    SELECT CASE Number2#
                        CASE -1, 0, 1
                            Temp# = Number1# OR Number2#
                            LastToken = True
                            EXIT SUB
                    END SELECT
            END SELECT
            ERROR 2
        CASE "TXOR"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Number1# = Temp#
            CALL GetToken
            CALL Parse1(Temp#)
            Number2# = Temp#
            CALL GetToken4
            SELECT CASE Number1#
                CASE -1, 0, 1
                    SELECT CASE Number2#
                        CASE -1, 0, 1
                            Temp# = Number1# XOR Number2#
                            LastToken = True
                            EXIT SUB
                    END SELECT
            END SELECT
            ERROR 2
            ' data constants
        CASE "DATALINE"
            Temp# = DataLine
            LastToken = True
        CASE "DATANUMBER"
            Temp# = DataNumber
            LastToken = True
            ' date/time functions
        CASE "CLOCK"
            Temp# = TIMER
            LastToken = True
        CASE "NOW"
            Temp# = TIMER
            LastToken = True
        CASE "DATE$"
            Out3 = DATE$
            LastToken = False
        CASE "TIME$"
            Out3 = TIME$
            LastToken = False
        CASE "TIMER"
            Temp# = TIMER
            LastToken = True
            ' input functions
        CASE "INKEY$"
            ' read keyboard directly
            LOCATE , , Visible
            Out3 = INKEY$
            LastToken = False
        CASE "INPUT$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            IF Temp# <= 0# OR Temp# > 32767# THEN
                ERROR 2 ' syntax error
            END IF
            Chars% = CINT(Temp#)
            IF Strng = "," THEN
                CALL GetToken
                CALL Parse1(Temp#)
                FileNum% = CINT(Temp#)
                IF FileNum% <= 0 OR FileNum% > MaxFiles THEN
                    ERROR 126
                    EXIT SUB
                END IF
                Out3 = INPUT$(Chars%, FileNum%)
            ELSE
                ' read keyboard directly
                LOCATE , , Visible
                Out3 = Nul
                DO
                    _LIMIT 50
                    I$ = INKEY$
                    IF LEN(I$) THEN
                        Out3 = Out3 + I$ ' get character
                    END IF
                    IF LEN(Out3) >= Chars% THEN ' check length
                        EXIT DO
                    END IF
                LOOP
            END IF
            CALL GetToken4
            LastToken = False
            ' special line printer functions
        CASE "LPOS"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            VarX = CINT(Temp#)
            IF VarX >= 0 AND VarX <= 3 THEN
                Temp# = LPOS(VarX)
            ELSE
                ERROR 161
            END IF
            CALL GetToken4
            Out3 = Nul
            LastToken = True
        CASE "LPRINT"
            Out3 = "LPRINT"
            LastToken = False
            ' special debug constants
        CASE "TEMPDIR$"
            Out3 = DRX$
            LastToken = False
        CASE "NODE"
            Temp# = Node
            LastToken = True
        CASE "DEBUG"
            Temp# = DebugActive
            LastToken = True
        CASE "LLINES"
            Temp# = ListLines
            LastToken = True
        CASE "LBOUND"
            Temp# = 1
            LastToken = True
        CASE "UBOUND"
            Temp# = MaxArrays
            LastToken = True
            ' special input loop time slice releaser
        CASE "SLICE$"
            Out3 = Nul
            T! = TIMER
            DO
                _LIMIT 50
                E! = TIMER - T!
                IF E! < SFalse THEN
                    E! = E! + 86400!
                END IF
                IF E! > .01! THEN
                    EXIT DO
                END IF
            LOOP
            LastToken = False
            ' conversion/calculation functions
        CASE "BIN$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Out3 = Nul
            IF Temp# >= False THEN
                Digits = False
                DO
                    IF 2 ^ (Digits + 1) > Temp# THEN
                        EXIT DO
                    END IF
                    Digits = Digits + 1
                LOOP
                FOR Power = Digits TO 0 STEP -1
                    IF Temp# - 2 ^ Power >= False THEN
                        Temp# = Temp# - 2 ^ Power
                        Out3 = Out3 + "1"
                    ELSE
                        Out3 = Out3 + "0"
                    END IF
                NEXT
            END IF
            CALL GetToken4
            LastToken = False
        CASE "CHR$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Out3 = CHR$(Temp#)
            CALL GetToken4
            LastToken = False
        CASE "HEX$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Out3 = HEX$(Temp#)
            CALL GetToken4
            LastToken = False
        CASE "OCT$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Out3 = OCT$(Temp#)
            CALL GetToken4
            LastToken = False
        CASE "STR$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Out3 = STR$(Temp#)
            CALL GetToken4
            LastToken = False
        CASE "LCASE$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Out3 = LCASE$(Out3)
            CALL GetToken4
            LastToken = False
        CASE "UCASE$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Out3 = UCASE$(Out3)
            CALL GetToken4
            LastToken = False
        CASE "LTRIM$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Out3 = LTRIM$(Out3)
            CALL GetToken4
            LastToken = False
        CASE "RTRIM$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Out3 = RTRIM$(Out3)
            CALL GetToken4
            LastToken = False
        CASE "TRIM$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Out3 = LTRIM$(Out3)
            Out3 = RTRIM$(Out3)
            CALL GetToken4
            LastToken = False
        CASE "STRIM$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Out3 = STRIM$(Out3)
            CALL GetToken4
            LastToken = False
        CASE "TTRIM$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Out3 = LTRIM$(Out3)
            Out3 = RTRIM$(Out3)
            Out3 = TTRIM$(Out3, True)
            CALL GetToken4
            LastToken = False
        CASE "UTRIM$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Out3 = LTRIM$(Out3)
            Out3 = RTRIM$(Out3)
            Out3 = TTRIM$(Out3, False)
            CALL GetToken4
            LastToken = False
        CASE "XTRIM$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Out3 = LTRIM$(Out3)
            Out3 = RTRIM$(Out3)
            Out3 = XTRIM$(Out3, True)
            CALL GetToken4
            LastToken = False
        CASE "ZTRIM$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Out3 = LTRIM$(Out3)
            Out3 = RTRIM$(Out3)
            Out3 = XTRIM$(Out3, False)
            CALL GetToken4
            LastToken = False
        CASE "STRIP$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            FOR Var1 = 1 TO LEN(WhiteSpace)
                V$ = MID$(WhiteSpace, Var1, 1)
                WHILE INSTR(Out3, V$)
                    Var2 = INSTR(Out3, V$)
                    Out3 = LEFT$(Out3, Var2 - 1) + MID$(Out3, Var2 + 1)
                WEND
            NEXT
            CALL GetToken4
            LastToken = False
        CASE "SPACE$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Out3 = SPACE$(CINT(Temp#))
            CALL GetToken4
            LastToken = False
        CASE "FORMATS$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Out3 = FormatString$(Temp#)
            CALL GetToken4
            LastToken = False
        CASE "FORMAT$"
            ' QB64 has no FORMAT$ for date/time strings.
            ERROR 73 ' feature unavailable.
        CASE "MID$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            StoredString$ = Out3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp4# = Temp#
            IF Strng = "," THEN
                CALL GetToken
                CALL Parse1(Temp#)
                Length# = Temp#
                Out3 = MID$(StoredString$, Temp4#, Length#)
            ELSE
                Out3 = MID$(StoredString$, Temp4#)
            END IF
            CALL GetToken4
            LastToken = False
        CASE "REMID$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            StoredString$ = Out3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp4# = Temp#
            CALL GetToken
            CALL Parse1(Temp#)
            Length# = Temp#
            Out3 = LEFT$(StoredString$, Temp4# - 1) + MID$(StoredString$, Temp4# + Length#)
            CALL GetToken4
            LastToken = False
        CASE "DEMID$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            String1$ = Out3
            CALL GetToken
            CALL Parse1(Temp#)
            IF LEN(String1$) > False AND LEN(Out3) > False THEN
                Imbedded = INSTR(String1$, Out3)
                WHILE Imbedded
                    String1$ = LEFT$(String1$, Imbedded - 1) + MID$(String1$, Imbedded + LEN(Out3))
                    Imbedded = INSTR(String1$, Out3)
                WEND
            END IF
            Out3 = String1$
            CALL GetToken4
            LastToken = False
        CASE "REPLACE$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            String1$ = Out3
            CALL GetToken
            CALL Parse1(Temp#)
            String2$ = Out3
            CALL GetToken
            CALL Parse1(Temp#)
            String3$ = Out3
            IF String1$ = Nul OR String2$ = Nul OR String2$ = String3$ THEN
                Out3 = String1$
                EXIT SUB
            END IF
            Temp1 = 1
            DO
                IF String1$ = Nul THEN
                    EXIT DO
                END IF
                Var1 = INSTR(Temp1, String1$, String2$)
                IF Var1 = False THEN
                    EXIT DO
                END IF
                String1$ = LEFT$(String1$, Var1 - 1) + String3$ + MID$(String1$, Var1 + LEN(String2$))
                Temp1 = Temp1 + LEN(String3$)
            LOOP
            Out3 = String1$
            CALL GetToken4
            LastToken = False
        CASE "LEFT$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            StoredString$ = Out3
            CALL GetToken
            CALL Parse1(Temp#)
            Out3 = LEFT$(StoredString$, Temp#)
            CALL GetToken4
            LastToken = False
        CASE "RIGHT$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            StoredString$ = Out3
            CALL GetToken
            CALL Parse1(Temp#)
            Out3 = RIGHT$(StoredString$, Temp#)
            CALL GetToken4
            LastToken = False
        CASE "STRING$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Number# = Temp#
            CALL GetToken
            CALL Parse1(Temp#)
            IF LastToken THEN
                Out3 = STRING$(Number#, Temp#)
            ELSE
                Out3 = STRING$(Number#, Out3)
            END IF
            CALL GetToken4
            LastToken = False
        CASE "ENCRYPT$"
            PrimeKey2 = PrimeKey
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            V$ = Out3
            Token2 = LastToken
            IF Strng = "," THEN
                CALL GetToken
                CALL Parse1(Temp2#)
                PrimeKey2 = Temp2#
            END IF
            Out3 = V$
            IF Token2 THEN
                Out3 = CHR$(Temp# XOR PrimeKey2)
            ELSE
                FOR V = 1 TO LEN(Out3)
                    MID$(Out3, V, 1) = CHR$(ASC(MID$(Out3, V, 1)) XOR PrimeKey2)
                NEXT
            END IF
            CALL GetToken4
            LastToken = False
        CASE "STOPWAV" ' stops .wav file
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            IF LastToken THEN
                VarX = CINT(Temp#)
                _SNDSTOP VarX
            END IF
            CALL GetToken4
            LastToken = True
        CASE "WAV" ' plays .wav file
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            IF LastToken THEN
                VarX = CINT(Temp#)
                IF VarX >= 1 AND VarX <= 12 THEN
                    Out3 = Nul
                    SELECT CASE VarX
                        CASE 1
                            Out3 = "Laser.wav"
                        CASE 2
                            Out3 = "Ringin.wav"
                        CASE 3
                            Out3 = "Carrier.wav"
                        CASE 4
                            Out3 = "Boing.wav"
                        CASE 5
                            Out3 = "Bang.wav"
                        CASE 6
                            Out3 = "Connect.wav"
                        CASE 7
                            Out3 = "Complete.wav"
                        CASE 8
                            Out3 = "Gunshot.wav"
                        CASE 9
                            Out3 = "Ricochet.wav"
                        CASE 10
                            Out3 = "Whoosh.wav"
                        CASE 11
                            Out3 = "Glass.wav"
                        CASE 12
                            Out3 = "Cashreg.wav"
                        CASE ELSE
                            ERROR 92
                            EXIT SUB
                    END SELECT
                END IF
            END IF
            Temp# = -1#
            IF _FILEEXISTS(Out3) THEN
                h = _SNDOPEN(Out3) ' get file handle
                IF h = 0 THEN
                    Temp# = 0#
                ELSE
                    Temp# = h
                    _SNDPLAY h
                    _SNDCLOSE h
                END IF
            ELSE
                Temp# = 0#
                ERROR 53
            END IF
            CALL GetToken4
            LastToken = True

            ' plays music file
            '    supports: WAVE,OGG,AIFF,RIFF,VOC,MP3,MOD,MIDI
        CASE "WAV$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            IF LastToken THEN
                Out3 = Nul
                Var = CINT(Temp#)
                IF Var >= 1 AND Var <= 9 THEN
                    SELECT CASE Var
                        CASE 1
                            Out3 = "addctdto.mid"
                        CASE 2
                            Out3 = "africa.mid"
                        CASE 3
                            Out3 = "burning.mid"
                        CASE 4
                            Out3 = "hotel.mid"
                        CASE 5
                            Out3 = "imagine5.mid"
                        CASE 6
                            Out3 = "panama.mid"
                        CASE 7
                            Out3 = "stayin.mid"
                        CASE 8
                            Out3 = "strshptr.mid"
                        CASE 9
                            Out3 = "wtj.mid"
                    END SELECT
                END IF
            END IF
            Temp# = -1#
            IF _FILEEXISTS(Out3) THEN
                h = _SNDOPEN(Out3) ' get file handle
                IF h = 0 THEN
                    Temp# = 0#
                ELSE
                    Temp# = h
                    _SNDPLAY h
                    _SNDCLOSE h
                END IF
            ELSE
                Temp# = 0#
                ERROR 53
            END IF
            CALL GetToken4
            LastToken = True

            ' gets music file length in seconds
            '    supports: WAVE,OGG,AIFF,RIFF,VOC
        CASE "WAVLEN"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = 0#
            IF _FILEEXISTS(Out3) THEN
                h = _SNDOPEN(Out3, "LEN") ' get file handle
                IF h > 0 THEN
                    Temp# = _SNDLEN(h)
                    _SNDCLOSE h
                END IF
            ELSE
                ERROR 53
            END IF
            CALL GetToken4
            LastToken = True

            ' constant functions
        CASE "AUTHOR$"
            Out3 = Statements$(MaxStatements + 1)
            LastToken = False
        CASE "EMAIL$"
            Out3 = Statements$(MaxStatements + 2)
            LastToken = False
        CASE "URL$"
            Out3 = Statements$(MaxStatements + 3)
            LastToken = False
        CASE "VERSION$"
            Out3 = Version
            LastToken = False
        CASE "RELEASE$"
            Out3 = Release
            LastToken = False
        CASE "COMMAND$"
            Out3 = CommandLine
            LastToken = False
        CASE "PROGRAM$"
            Out3 = ProgramName
            LastToken = False
        CASE "PUBLISH$"
            Out3 = PublishDate
            LastToken = False
        CASE "COOKIE$"
            IF RND > .5 THEN
                Out3 = "You owe me a sugar cookie for writing this program and I want it now!!"
            ELSE
                Out3 = "No one cares what the code looks like as long as it works!"
            END IF
            LastToken = False
        CASE "ERROR"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            ERROR CINT(Temp#)
            CALL GetToken4
            LastToken = True
        CASE "OS$"
            Out3 = _OS$
            LastToken = False
        CASE "MACHINE$"
            ' check net path.
            Out3 = Nul
            Var$ = ENVIRON$("COMPUTERNAME")
            IF LEN(Var$) THEN
                Out3 = Var$
            END IF
            LastToken = False
        CASE "PRIMEKEY"
            Temp# = PrimeKey
            LastToken = True
        CASE "TICKS"
            Temp# = 18.20648
            LastToken = True
        CASE "MAXINT"
            Temp# = 32766#
            LastToken = True
            ' numeric/string constant functions
        CASE "LASTLINE"
            Temp# = LastLine
            LastToken = True
        CASE "LINENUMBER"
            Temp# = ProgramLine
            LastToken = True
        CASE "PROGRAMLINE"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Var2 = CINT(Temp#)
            IF Var2 > False AND Var2 <= MaxLines THEN
                IF LEN(Program(Var2)) <> False THEN
                    Out3 = Program(Var2)
                END IF
            END IF
            CALL GetToken4
            LastToken = False
        CASE "HISTORYCOUNT"
            CALL GetToken
            CALL GetToken
            CALL Parse1(Temp#)
            Var1 = CINT(Temp#)
            IF Var1 >= 1 AND Var1 <= 3 THEN
                Temp# = HistoryCount2(Var1)
            END IF
            CALL GetToken4
            LastToken = True
        CASE "HISTORY"
            CALL GetToken
            CALL GetToken
            CALL Parse1(Temp#)
            Var1 = CINT(Temp#)
            CALL GetToken
            CALL Parse1(Temp#)
            Var2 = CINT(Temp#)
            IF Var1 >= 1 AND Var1 <= 3 THEN
                IF Var2 > False AND Var2 <= MaxHistory THEN
                    IF LEN(RTRIM$(History2(Var1, Var2))) <> False THEN
                        Out3 = RTRIM$(History2(Var1, Var2))
                    END IF
                END IF
            END IF
            CALL GetToken4
            LastToken = False
        CASE "MAXARRAYS"
            Temp# = MaxArrays
            LastToken = True
        CASE "MAXFUNCTIONS"
            Temp# = MaxFunctions
            LastToken = True
        CASE "MAXHISTORY"
            Temp# = MaxHistory
            LastToken = True
        CASE "MAXLINES"
            Temp# = MaxLines
            LastToken = True
        CASE "MAXFNLENGTH"
            Temp# = MaxFNlength
            LastToken = True
        CASE "MAXNESTGOSUB"
            Temp# = MaxNestGosub
            LastToken = True
        CASE "MAXRECURSE"
            Temp# = MaxRecurse
            LastToken = True
            ' other functions
        CASE "PMAP"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Number% = CINT(Temp#)
            CALL GetToken
            CALL Parse1(Temp#)
            MapType% = CINT(Temp#)
            Temp# = PMAP(Number%, MapType%)
            CALL GetToken4
            LastToken = True
        CASE "VARSEG"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            IF LastToken THEN
                VarSeg2 = Temp#
                Temp# = VARSEG(VarSeg2)
                IF Temp# < 0# THEN
                    Temp# = Temp# + 65536#
                END IF
            ELSE
                Length = LEN(Out3)
                REDIM VarSeg3(1 TO Length) AS INTEGER
                FOR Count = 1 TO Length
                    VarSeg3(Count) = ASC(MID$(Out3, Count, 1))
                NEXT
                Temp# = VARSEG(VarSeg3(1))
                IF Temp# < 0# THEN
                    Temp# = Temp# + 65536#
                END IF
            END IF
            CALL GetToken4
            LastToken = True
        CASE "VARPTR$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            IF LastToken THEN
                VarSeg2 = Temp#
                Out3 = VARPTR$(VarSeg2)
            ELSE
                VarSeg1 = Out3
                Out3 = VARPTR$(VarSeg1)
            END IF
            CALL GetToken4
            LastToken = False
        CASE "VARPTR"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            IF LastToken THEN
                VarSeg2 = Temp#
                Temp# = VARPTR(VarSeg2)
                IF Temp# < 0# THEN
                    Temp# = Temp# + 65536#
                END IF
            ELSE
                Length = LEN(Out3)
                REDIM VarSeg3(1 TO Length) AS INTEGER
                FOR Count = 1 TO Length
                    VarSeg3(Count) = ASC(MID$(Out3, Count, 1))
                NEXT
                Temp# = VARPTR(VarSeg3(1))
                IF Temp# < 0# THEN
                    Temp# = Temp# + 65536#
                END IF
            END IF
            CALL GetToken4
            LastToken = True
        CASE "BUFFER"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            CaseValue = Temp#
            SELECT CASE CaseValue
                CASE 1
                    Temp# = VarSeg2
                    LastToken = True
                CASE 2
                    Out3 = Nul
                    Length = UBOUND(VarSeg3)
                    FOR Count = 1 TO Length
                        Out3 = Out3 + CHR$(VarSeg3(Count))
                    NEXT
                    LastToken = False
                CASE 3
                    Elements = INT((ArraySize + 1) / 2)
                    FOR Count = 1 TO Elements
                        GraphicsScreen(Count) = VarSeg3(Count)
                    NEXT
                    LastToken = True
            END SELECT
            CALL GetToken4
        CASE "GRPHSEG"
            Elements = INT((ArraySize + 1) / 2)
            REDIM VarSeg3(1 TO Elements) AS INTEGER
            FOR Count = 1 TO Elements
                VarSeg3(Count) = GraphicsScreen(Count)
            NEXT
            Temp# = VARSEG(VarSeg3(1))
            LastToken = True
        CASE "GRPHPTR"
            Elements = INT((ArraySize + 1) / 2)
            REDIM VarSeg3(1 TO Elements) AS INTEGER
            FOR Count = 1 TO Elements
                VarSeg3(Count) = GraphicsScreen(Count)
            NEXT
            Temp# = VARPTR(VarSeg3(1))
            LastToken = True
        CASE "PLAY"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = PLAY(Temp#)
            CALL GetToken4
            LastToken = True
            ' more numeric functions
        CASE "ABS"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = ABS(Temp#)
            CALL GetToken4
            LastToken = True
        CASE "ASC"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = ASC(Out3)
            CALL GetToken4
            LastToken = True
        CASE "EXP"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = EXP(Temp#)
            CALL GetToken4
            LastToken = True
        CASE "FBN" ' calculate xth fibonachi value
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            FiboA# = 1
            FiboB# = 1
            IF Temp# >= 1 THEN
                FOR FiboNumber# = 1 TO Temp# - 1
                    FiboTemp# = FiboB#
                    FiboB# = FiboA# + FiboB#
                    FiboA# = FiboTemp#
                NEXT
            END IF
            Temp# = FiboB#
            CALL GetToken4
            LastToken = True
        CASE "FCT"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Factorial# = 1
            FactorialCount# = INT(Temp#)
            IF FactorialCount# >= 1 THEN
                FOR FactorialCount# = 1 TO Temp#
                    Factorial# = Factorial# * FactorialCount#
                NEXT
            END IF
            Temp# = Factorial#
            CALL GetToken4
            LastToken = True
        CASE "FIX"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = FIX(Temp#)
            CALL GetToken4
            LastToken = True
        CASE "INP"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = INP(CINT(Temp#))
            CALL GetToken4
            LastToken = True
        CASE "INSTR"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            IF LastToken THEN
                Temp4# = Temp#
                CALL GetToken
                CALL Parse1(Temp#)
                StoredString$ = Out3
                CALL GetToken
                CALL Parse1(Temp#)
                Temp# = INSTR(Temp4#, StoredString$, Out3)
            ELSE
                StoredString$ = Out3
                CALL GetToken
                CALL Parse1(Temp#)
                Temp# = INSTR(StoredString$, Out3)
            END IF
            CALL GetToken4
            LastToken = True
        CASE "INT"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = INT(Temp#)
            CALL GetToken4
            LastToken = True
        CASE "LEN"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = CDBL(LEN(Out3))
            CALL GetToken4
            LastToken = True
        CASE "LOG"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = LOG(Temp#)
            CALL GetToken4
            LastToken = True
        CASE "GCM"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Number1# = Temp#
            CALL GetToken
            CALL Parse1(Temp#)
            Number2# = Temp#
            ' find last factor which divides into both numbers
            Factor1# = 1
            Number3# = Number1#
            FOR Factor2# = 2 TO Number1#
                DO
                    IF Number3# / Factor2# = Number3# \ Factor2# THEN
                        IF Number2# / Factor2# = Number2# \ Factor2# THEN
                            IF Factor2# > Factor1# THEN
                                Factor1# = Factor2#
                            END IF
                        END IF
                        Number3# = Number3# / Factor2#
                    ELSE
                        EXIT DO
                    END IF
                LOOP
            NEXT
            Temp# = Factor1#
            CALL GetToken4
            LastToken = True
        CASE "LCD"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Number1# = Temp#
            CALL GetToken
            CALL Parse1(Temp#)
            Number2# = Temp#
            ' find first factor which divides into both numbers
            Factor1# = 0
            FOR Factor2# = 2 TO Number1#
                IF Number1# / Factor2# = Number1# \ Factor2# THEN
                    IF Number2# / Factor2# = Number2# \ Factor2# THEN
                        Factor1# = Factor2#
                        EXIT FOR
                    END IF
                END IF
            NEXT
            IF Factor1# = 0# THEN
                Factor1# = 1#
            END IF
            IF Factor1# = Number2# THEN
                Factor1# = 1#
            END IF
            Temp# = Factor1#
            CALL GetToken4
            LastToken = True
        CASE "ISEVEN"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = (Temp# MOD 2#) = 0#
            CALL GetToken4
            LastToken = True
        CASE "ISODD"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = (Temp# MOD 2#) = 1#
            CALL GetToken4
            LastToken = True
        CASE "ISPRM" ' calculate x is prime
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Prime# = INT(Temp#)
            PrimeFlag = True
            IF Prime# > 2# THEN
                FOR LoopCount# = 2# TO INT(SQR(Prime#))
                    IF Prime# / LoopCount# = INT(Prime# / LoopCount#) THEN
                        PrimeFlag = False
                        EXIT FOR
                    END IF
                NEXT
            END IF
            IF PrimeFlag = False THEN
                Temp# = 0#
            ELSE
                Temp# = -1#
            END IF
            CALL GetToken4
            LastToken = True
        CASE "PRF" ' calculate nth perfect number
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Perfect# = INT(Temp#)
            SELECT CASE Perfect# ' x = 1,2,4,6,12,16,18,30
                CASE 1#
                    X# = 1#
                CASE 2#
                    X# = 2#
                CASE 3#
                    X# = 4#
                CASE 4#
                    X# = 6#
                CASE 5#
                    X# = 12#
                CASE 6#
                    X# = 16#
                CASE 7#
                    X# = 18#
                CASE ELSE
                    ERROR 131
            END SELECT
            ' equation for perfect number
            Temp# = 2 ^ X# * (2 ^ (X# + 1) - 1)
            CALL GetToken4
            LastToken = True
        CASE "PRM" ' calculate xth prime
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            PrimeNumber# = INT(Temp#)
            Prime# = 1
            IF PrimeNumber# > False THEN
                PrimeCounter# = False
                DO
                    Prime# = Prime# + 1
                    PrimeFlag = False
                    FOR Factor# = 2 TO INT(SQR(Prime#))
                        IF Prime# / Factor# = INT(Prime# / Factor#) THEN
                            PrimeFlag = True
                            EXIT FOR
                        END IF
                    NEXT
                    IF PrimeFlag = False THEN
                        PrimeCounter# = PrimeCounter# + 1
                    END IF
                    IF PrimeCounter# = PrimeNumber# THEN
                        EXIT DO
                    END IF
                LOOP
            END IF
            Temp# = Prime#
            CALL GetToken4
            LastToken = True
        CASE "SGN"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = SGN(Temp#)
            CALL GetToken4
            LastToken = True
        CASE "SQR"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            IF Temp# < 0# THEN
                ERROR 157
            ELSE
                Temp# = SQR(Temp#)
            END IF
            CALL GetToken4
            LastToken = True
        CASE "CBR"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = Temp# ^ (1# / 3#)
            CALL GetToken4
            LastToken = True
        CASE "NTH"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Number# = Temp#
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = Number# ^ (1# / Temp#)
            CALL GetToken4
            LastToken = True
        CASE "PWR"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Number# = Temp#
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = Number# ^ Temp#
            CALL GetToken4
            LastToken = True
        CASE "VAL"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = VAL(Out3)
            CALL GetToken4
            LastToken = True
        CASE "PEEK"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = PEEK(Temp#)
            CALL GetToken4
            LastToken = True
        CASE "MKI$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Out3 = MKI$(Temp#)
            CALL GetToken4
            LastToken = False
        CASE "MKS$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Out3 = MKS$(Temp#)
            CALL GetToken4
            LastToken = False
        CASE "MKD$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Out3 = MKD$(Temp#)
            CALL GetToken4
            LastToken = False
        CASE "CVI"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = CVI(Out3)
            CALL GetToken4
            LastToken = True
        CASE "CVS"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = CVS(Out3)
            CALL GetToken4
            LastToken = True
        CASE "CVD"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = CVD(Out3)
            CALL GetToken4
            LastToken = True
        CASE "EOF"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp3#)
            Temp# = EOF(CINT(Temp3#))
            CALL GetToken4
            LastToken = True
        CASE "LOC"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp3#)
            Temp# = LOC(CINT(Temp3#))
            CALL GetToken4
            LastToken = True
        CASE "LOF"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp3#)
            Temp# = LOF(CINT(Temp3#))
            CALL GetToken4
            LastToken = True
        CASE "EOD" ' end-of-data
            AllowExtra = 1
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp3#)
            CALL GetToken4

            ' search for data statement
            X = 0
            FOR V = 1 TO LastLine
                V$ = Program(V)
                V$ = STRIM$(V$)
                V$ = UCASE$(V$)
                IF LEFT$(V$, 4) = "DATA" THEN
                    X = -1
                    EXIT FOR
                END IF
            NEXT
            IF X = 0 THEN
                Temp# = -1
                Out3 = "-1"
                LastToken = True
                AllowExtra = 0
                EXIT SUB
            END IF

            V1 = DataLine
            V2 = DataNumber
            StoredOut2$ = Out2
            StoredTokenIndex = TokenIndex
            CALL ReadDataElement(Var)
            DataLine = V1
            DataNumber = V2
            Out2 = StoredOut2$
            TokenIndex = StoredTokenIndex

            Temp# = CDBL(Var)
            Out3 = STR$(Var)
            LastToken = True
            AllowExtra = 0
        CASE "TOD" ' type-of-data
            AllowExtra = 1
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp3#)
            CALL GetToken4

            ' search for data statement
            X = 0
            FOR V = 1 TO LastLine
                V$ = Program(V)
                V$ = STRIM$(V$)
                V$ = UCASE$(V$)
                IF LEFT$(V$, 4) = "DATA" THEN
                    X = -1
                    EXIT FOR
                END IF
            NEXT
            IF X = 0 THEN
                Temp# = 0
                Out3 = "0"
                LastToken = True
                AllowExtra = 0
                EXIT SUB
            END IF

            V1 = DataLine
            V2 = DataNumber
            StoredOut2$ = Out2
            StoredTokenIndex = TokenIndex
            CALL ReadDataElement(Var)
            DataLine = V1
            DataNumber = V2
            Out2 = StoredOut2$
            TokenIndex = StoredTokenIndex

            ' store datatype of next data element
            IF Var = False THEN
                IF LastToken THEN
                    Temp# = 1# ' numeric
                ELSE
                    Temp# = 2# ' string
                END IF
            ELSE
                Temp# = Dfalse ' no more data
            END IF
            LastToken = True
            Out3 = STR$(Temp#)
            AllowExtra = 0
        CASE "ISDATA" ' is-type-of-data
            AllowExtra = 1
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp3#)
            CALL GetToken4
            SearchType = Temp3#

            ' search for data statement
            X = 0
            FOR V = 1 TO LastLine
                V$ = Program(V)
                V$ = STRIM$(V$)
                V$ = UCASE$(V$)
                IF LEFT$(V$, 4) = "DATA" THEN
                    X = -1
                    EXIT FOR
                END IF
            NEXT
            IF X = 0 THEN
                IF SearchType = 0 THEN
                    Temp# = -1
                    Out3 = "-1"
                ELSE
                    Temp# = 0
                    Out3 = "0"
                END IF
                LastToken = True
                AllowExtra = 0
                EXIT SUB
            END IF

            V1 = DataLine
            V2 = DataNumber
            StoredOut2$ = Out2
            StoredTokenIndex = TokenIndex
            CALL ReadDataElement(Var)
            DataLine = V1
            DataNumber = V2
            Out2 = StoredOut2$
            TokenIndex = StoredTokenIndex

            ' store datatype of next data element
            Temp# = 0#
            SELECT CASE SearchType
                CASE 0 ' more data
                    IF Var THEN
                        Temp# = -1
                    END IF
                CASE 1 ' numeric
                    IF Var = False THEN
                        IF LastToken THEN
                            Temp# = -1
                        END IF
                    END IF
                CASE 2 ' string
                    IF Var = False THEN
                        IF LastToken = 0 THEN
                            Temp# = -1
                        END IF
                    END IF
            END SELECT

            LastToken = True
            Out3 = STR$(Temp#)
            AllowExtra = 0
            ' disk functions
        CASE "CAPITALIZE"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            CALL Capitalize(Out3)
            CALL GetToken4
            LastToken = False
        CASE "SUFFIX"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            CALL Suffix(Temp#, Out3)
            CALL GetToken4
            LastToken = False
        CASE "FILEEXISTS"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = _FILEEXISTS(Out3)
            CALL GetToken4
            LastToken = True
        CASE "DIREXISTS"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = _DIREXISTS(Out3)
            CALL GetToken4
            LastToken = True
        CASE "DRIVEEXISTS"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Var$ = Nul
            IF LastToken THEN
                Var = CINT(Temp#)
                IF Var >= 1 AND Var <= 26 THEN
                    Var$ = CHR$(Var + 64)
                END IF
            ELSE
                Var = ASC(UCASE$(Out3))
                IF Var >= 65 AND Var <= 90 THEN
                    Var$ = CHR$(Var)
                    Var = Var - 64
                END IF
            END IF
            Temp# = 0#
            IF LEN(Var$) THEN
                Out3 = Var$
                IF DRIVEEXISTS(Var) = 0 THEN
                    Temp# = -1#
                END IF
            END IF
            CALL GetToken4
            LastToken = True
        CASE "DRIVETYPE"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Var$ = Nul
            IF LastToken THEN
                Var = CINT(Temp#)
                IF Var >= 1 AND Var <= 26 THEN
                    Var$ = CHR$(Var + 64)
                END IF
            ELSE
                Var = ASC(UCASE$(Out3))
                IF Var >= 65 AND Var <= 90 THEN
                    Var$ = CHR$(Var)
                    Var = Var - 64
                END IF
            END IF
            Out3 = Nul
            IF LEN(Var$) THEN
                IF DRIVEEXISTS(Var) = 0 THEN
                    Out3 = DriveType
                END IF
            END IF
            CALL GetToken4
            LastToken = False
        CASE "AMBIG$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Out3 = Ambiguate$(Out3)
            CALL GetToken4
            LastToken = False
        CASE "CURDIR$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Out3 = CurDir$
            CALL GetToken4
            LastToken = False
        CASE "ENVIRON$"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            IF LastToken THEN
                Var = CINT(Temp#)
                Out3 = ENVIRON$(Var)
            ELSE
                Out3 = ENVIRON$(Out3)
            END IF
            CALL GetToken4
            LastToken = False
        CASE "DIR$", "FILEDIR"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            VarX$ = Out3
            CALL FileDir(VarX$)
            CALL GetToken4
            LastToken = False
        CASE "DIRX$", "FILEDIRX"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            VarX$ = Out3
            CALL FileDirX(VarX$)
            CALL GetToken4
            LastToken = False
        CASE "FILES"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            CALL ListFiles(Out3, True)
            ErrorType2 = 0
            CALL GetToken4
            LastToken = False
        CASE "DIRS"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            CALL ListFiles(Out3, False)
            ErrorType2 = 0
            CALL GetToken4
            LastToken = False
        CASE "DRIVES"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Var = 0
            Var$ = Nul
            IF LastToken THEN
                Var = CINT(Temp#)
                IF Var >= 0 AND Var <= 26 THEN
                    CALL ListDrives("", Var)
                    Temp# = -1#
                ELSE
                    Temp# = 0#
                END IF
            ELSE
                Var$ = UCASE$(Out3)
                CALL ListDrives(Var$, 0)
                Temp# = -1#
            END IF
            CALL GetToken4
            LastToken = True
        CASE "FILEDATE"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            CALL FileDate(Out3)
            CALL GetToken4
            LastToken = False
        CASE "FILETIME"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            CALL FileTime(Out3)
            CALL GetToken4
            LastToken = False
        CASE "FILESIZE"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            CALL FileSize(Temp#)
            CALL GetToken4
            LastToken = True
        CASE "FILEATTR"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            CALL FileAttr(Temp#)
            CALL GetToken4
            LastToken = True
        CASE "FILEBITS"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            CALL FileAttr(Temp#)
            CALL GetToken4
            Out3 = SPACE$(7)
            IF (Temp# AND &H20) = &H20 THEN
                MID$(Out3, 1, 1) = "A" ' archive
            END IF
            IF (Temp# AND &H10) = &H10 THEN
                MID$(Out3, 2, 1) = "D" ' directory
            END IF
            IF (Temp# AND &H4) = &H4 THEN
                MID$(Out3, 3, 1) = "S" ' system
            END IF
            IF (Temp# AND &H2) = &H2 THEN
                MID$(Out3, 4, 1) = "H" ' hidden
            END IF
            IF (Temp# AND &H1) = &H1 THEN
                MID$(Out3, 5, 1) = "R" ' read-only
            END IF
            IF (Temp# AND &H800) = &H800 THEN
                MID$(Out3, 6, 1) = "C" ' compressed
            END IF
            IF (Temp# AND &H4000) = &H4000 THEN
                MID$(Out3, 7, 1) = "E" ' encrypted
            END IF
            LastToken = False
        CASE "VLABEL"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            IF LastToken THEN
                Var = CINT(Temp#)
                IF Var >= 1 AND Var <= 26 THEN
                    Out3 = CHR$(Var + 64)
                    Var$ = Out3
                ELSE
                    Out3 = Nul
                    Var$ = Nul
                END IF
            ELSE
                Var$ = UCASE$(Out3)
                IF Var$ >= "A" AND Var$ <= "Z" THEN
                    Out3 = Var$
                    Var = ASC(Out3) - 64
                ELSE
                    Out3 = Nul
                    Var$ = Nul
                END IF
            END IF
            LastToken = False
            IF LEN(Var$) THEN
                Temp# = 0#
                IF DRIVEEXISTS(Var) = 0 THEN
                    CALL Vlabel(Out3)
                ELSE
                    ERROR 166
                END IF
            ELSE
                ERROR 166
            END IF
            CALL GetToken4
        CASE "VSERIAL"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            IF LastToken THEN
                Var = CINT(Temp#)
                IF Var >= 1 AND Var <= 26 THEN
                    Out3 = CHR$(Var + 64)
                    Var$ = Out3
                ELSE
                    Out3 = Nul
                    Var$ = Nul
                END IF
            ELSE
                Var$ = UCASE$(Out3)
                IF Var$ >= "A" AND Var$ <= "Z" THEN
                    Out3 = Var$
                    Var = ASC(Var$) - 64
                ELSE
                    Out3 = Nul
                    Var$ = Nul
                END IF
            END IF
            LastToken = False
            IF LEN(Var$) THEN
                Temp# = 0#
                IF DRIVEEXISTS(Var) = 0 THEN
                    CALL Vserial(Out3)
                ELSE
                    ERROR 166
                END IF
            ELSE
                ERROR 166
            END IF
            CALL GetToken4
        CASE "VTYPE"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            IF LastToken THEN
                Var = CINT(Temp#)
                IF Var >= 1 AND Var <= 26 THEN
                    Out3 = CHR$(Var + 64)
                    Var$ = Out3
                ELSE
                    Out3 = Nul
                    Var$ = Nul
                END IF
            ELSE
                Var$ = UCASE$(Out3)
                IF Var$ >= "A" AND Var$ <= "Z" THEN
                    Out3 = Var$
                    Var = ASC(Out3) - 64
                ELSE
                    Out3 = Nul
                    Var$ = Nul
                END IF
            END IF
            LastToken = False
            IF LEN(Var$) THEN
                Temp# = 0#
                IF DRIVEEXISTS(Var) = 0 THEN
                    CALL Vtype(Out3)
                ELSE
                    ERROR 166
                END IF
            ELSE
                ERROR 166
            END IF
            CALL GetToken4
        CASE "DRV"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            IF LastToken THEN
                Var = CINT(Temp#)
                IF Var >= 1 AND Var <= 26 THEN
                    Out3 = CHR$(Var + 64)
                ELSE
                    Out3 = Nul
                END IF
            ELSE
                Var$ = UCASE$(Out3)
                IF Var$ >= "A" AND Var$ <= "Z" THEN
                    Out3 = Var$
                ELSE
                    Out3 = Nul
                END IF
            END IF
            IF LEN(Out3) THEN
                CALL FreeSpace(Out3)
                Temp# = INT(VAL(Out3))
            END IF
            LastToken = True
            CALL GetToken4
        CASE "TDRV"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            IF LastToken THEN
                Var = CINT(Temp#)
                IF Var >= 1 AND Var <= 26 THEN
                    Out3 = CHR$(Var + 64)
                ELSE
                    Out3 = Nul
                END IF
            ELSE
                Var$ = UCASE$(Out3)
                IF Var$ >= "A" AND Var$ <= "Z" THEN
                    Out3 = Var$
                ELSE
                    Out3 = Nul
                END IF
            END IF
            IF LEN(Out3) THEN
                CALL TotalSpace(Out3)
                Temp# = INT(VAL(Out3))
            END IF
            LastToken = True
            CALL GetToken4
        CASE "TEMPFILENAME"
            Out3 = TempName$
            LastToken = False

            ' bubble sort variable array ascending
        CASE "SORT"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            CALL GetToken4
            Var = CINT(Temp#)
            IF Var >= 1 AND Var <= 26 THEN
                FOR Var1 = 1 TO MaxArrays
                    FOR Var2 = Var1 + 1 TO MaxArrays
                        IF Arrays(Var, Var1) > Arrays(Var, Var2) THEN
                            SWAP Arrays(Var, Var1), Arrays(Var, Var2)
                        END IF
                    NEXT
                NEXT
                LastToken = True
                EXIT SUB
            END IF
            ERROR 2
            ' bubble sort variable array descending
        CASE "ZSORT"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            CALL GetToken4
            Var = CINT(Temp#)
            IF Var >= 1 AND Var <= 26 THEN
                FOR Var1 = 1 TO MaxArrays
                    FOR Var2 = Var1 + 1 TO MaxArrays
                        IF Arrays(Var, Var1) < Arrays(Var, Var2) THEN
                            SWAP Arrays(Var, Var1), Arrays(Var, Var2)
                        END IF
                    NEXT
                NEXT
                LastToken = True
                EXIT SUB
            END IF
            ERROR 2
            ' bubble sort variables
        CASE "ZSORT2"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            CALL GetToken4
            Var = CINT(Temp#)
            IF Var = 0 THEN
                ' ascending
                FOR Var1 = 1 TO 26
                    FOR Var2 = Var1 + 1 TO 26
                        IF Variables(Var1) > Variables(Var2) THEN
                            SWAP Variables(Var1), Variables(Var2)
                        END IF
                    NEXT
                NEXT
            ELSE
                ' descnding
                FOR Var1 = 1 TO 26
                    FOR Var2 = Var1 + 1 TO 26
                        IF Variables(Var1) < Variables(Var2) THEN
                            SWAP Variables(Var1), Variables(Var2)
                        END IF
                    NEXT
                NEXT
            END IF
            Temp# = -1
            LastToken = True
            EXIT SUB
            ' fill array with random values
        CASE "RNDARRAY"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Var = CINT(Temp#)
            CALL GetToken
            CALL Parse1(Temp#)
            VarX# = Temp#
            CALL GetToken4
            IF Var >= 1 AND Var <= 26 THEN
                FOR Var2 = 1 TO MaxArrays
                    Arrays(Var, Var2) = INT(RND * VarX# + 1)
                NEXT
                Temp# = Var
                LastToken = True
                EXIT SUB
            END IF
            ERROR 2
            ' fill variables with random values
        CASE "RNDARRAY2"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            CALL GetToken4
            FOR Var1 = 1 TO 26
                Variables(Var1) = INT(RND * Temp# + 1)
            NEXT
            Temp# = -1
            LastToken = True
            EXIT SUB
            ' get array value
        CASE "ARRAY"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Var1 = CINT(Temp#)
            CALL GetToken
            CALL Parse1(Temp#)
            Var2 = CINT(Temp#)
            CALL GetToken4
            IF Var1 >= 1 AND Var1 <= 26 THEN
                IF Var2 >= 1 AND Var2 <= MaxArrays THEN
                    Temp# = Arrays(Var1, Var2)
                    LastToken = True
                    EXIT SUB
                END IF
            END IF
            ERROR 2
            ' set array value
        CASE "SETARRAY"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Var1 = CINT(Temp#)
            CALL GetToken
            CALL Parse1(Temp#)
            Var2 = CINT(Temp#)
            CALL GetToken
            CALL Parse1(Temp#)
            VarX# = Temp#
            CALL GetToken4
            IF Var1 >= 1 AND Var1 <= 26 THEN
                IF Var2 >= 1 AND Var2 <= MaxArrays THEN
                    Arrays(Var1, Var2) = VarX#
                    Temp# = Var1
                    LastToken = True
                    EXIT SUB
                END IF
            END IF
            ERROR 2
            ' get variable value
        CASE "VARIABLE"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Var1 = CINT(Temp#)
            CALL GetToken4
            IF Var1 >= 1 AND Var1 <= 26 THEN
                Temp# = Variables(Var1)
                LastToken = True
                EXIT SUB
            END IF
            ERROR 2
            ' set variable value
        CASE "SETVARIABLE"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Var1 = CINT(Temp#)
            CALL GetToken
            CALL Parse1(Temp#)
            VarX# = Temp#
            CALL GetToken4
            IF Var1 >= 1 AND Var1 <= 26 THEN
                Variables(Var1) = VarX#
                Temp# = Var1
                LastToken = True
                EXIT SUB
            END IF
            ERROR 2

            REM Basic trigonometric functions..

        CASE "COS"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = COS(Temp#)
            CALL GetToken4
            LastToken = True
        CASE "SIN"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = SIN(Temp#)
            CALL GetToken4
            LastToken = True
        CASE "TAN"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = TAN(Temp#)
            CALL GetToken4
            LastToken = True

            REM Advanced trigonometric functions..

        CASE "ATN"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = ATN(Temp#)
            CALL GetToken4
            LastToken = True
        CASE "COT"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = COS(Temp#) / SIN(Temp#)
            CALL GetToken4
            LastToken = True
        CASE "CSC"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = 1# / SIN(Temp#)
            CALL GetToken4
            LastToken = True
        CASE "SEC"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = 1# / COS(Temp#)
            CALL GetToken4
            LastToken = True

            REM Note: PI equals ATN(1)*4 because TAN(PI/4)=1
            REM    and ATN(TAN(1))=1 is the only solution which derives PI.

            REM Remaining nonintrinsic trigonometric functions..

            'Inverse Cosine
        CASE "ARCCOS"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = ATN(-Temp# / SQR(-Temp# * Temp# + 1#)) + 2# * ATN(1#)
            CALL GetToken4
            LastToken = True
            'Inverse Cosecant
        CASE "ARCCOSEC"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = ATN(Temp# / SQR(Temp# * Temp# - 1#)) + (SGN(Temp#) - 1#) * (2# * ATN(1#))
            CALL GetToken4
            LastToken = True
            'Inverse Cotangent
        CASE "ARCCOTAN"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = ATN(Temp#) + 2# * ATN(1#)
            CALL GetToken4
            LastToken = True
            'Inverse Secant
        CASE "ARCSEC"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = ATN(Temp# / SQR(Temp# * Temp# - 1#)) + SGN((Temp#) - 1#) * (2# * ATN(1#))
            CALL GetToken4
            LastToken = True
            'Inverse Sine
        CASE "ARCSIN"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = ATN(Temp# / SQR(-Temp# * Temp# + 1#))
            CALL GetToken4
            LastToken = True
            'Inverse Hyperbolic Cosine
        CASE "HARCCOS"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = LOG(Temp# + SQR(Temp# * Temp# - 1#))
            CALL GetToken4
            LastToken = True
            'Inverse Hyperbolic Cosecant
        CASE "HARCCOSEC"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = LOG((SGN(Temp#) * SQR(Temp# * Temp# + 1#) + 1#) / Temp#)
            CALL GetToken4
            LastToken = True
            'Inverse Hyperbolic Cotangent
        CASE "HARCCOTAN"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = LOG((Temp# + 1#) / (Temp# - 1#)) / 2#
            CALL GetToken4
            LastToken = True
            'Inverse Hyperbolic Secant
        CASE "HARCSEC"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = LOG((SQR(-Temp# * Temp# + 1#) + 1#) / Temp#)
            CALL GetToken4
            LastToken = True
            'Inverse Hyperbolic Sine
        CASE "HARCSIN"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = LOG(Temp# + SQR(Temp# * Temp# + 1#))
            CALL GetToken4
            LastToken = True
            'Inverse Hyperbolic Tangent
        CASE "HARCTAN"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = LOG((1# + Temp#) / (1# - Temp#)) / 2#
            CALL GetToken4
            LastToken = True
            'Hyperbolic Cosine
        CASE "HCOS"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = (EXP(Temp#) + EXP(-Temp#)) / 2#
            CALL GetToken4
            LastToken = True
            'Hyperbolic Cosecant
        CASE "HCOSEC"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = 2# / (EXP(Temp#) - EXP(-Temp#))
            CALL GetToken4
            LastToken = True
            'Hyperbolic Cotangent
        CASE "HCOTAN"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = (EXP(Temp#) + EXP(-Temp#)) / (EXP(Temp#) - EXP(-Temp#))
            CALL GetToken4
            LastToken = True
            'Hyperbolic Secant
        CASE "HSEC"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = 2# / (EXP(Temp#) + EXP(-Temp#))
            CALL GetToken4
            LastToken = True
            'Hyperbolic Sine
        CASE "HSIN"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = (EXP(Temp#) - EXP(-Temp#)) / 2#
            CALL GetToken4
            LastToken = True
            'Hyperbolic Tangent
        CASE "HTAN"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = (EXP(Temp#) - EXP(-Temp#)) / (EXP(Temp#) + EXP(-Temp#))
            CALL GetToken4
            LastToken = True
            'Convert Degrees to Radians
        CASE "DEGTORAD"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = ((ATN(1#) * 4#) / 180#) * Temp#
            CALL GetToken4
            LastToken = True
            'Convert Radians to Degrees
        CASE "RADTODEG"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = (180# / (ATN(1#) * 4#)) * Temp#
            CALL GetToken4
            LastToken = True
            ' Hypotenuse
        CASE "HYPOT"
            CALL GetToken3
            CALL GetToken
            CALL Parse1(Temp#)
            Number# = Temp#
            CALL GetToken
            CALL Parse1(Temp#)
            Temp# = SQR(Number# * Number# + Temp# * Temp#)
            CALL GetToken4
            LastToken = True
        CASE ELSE
            IF AllowAlpha THEN
                Out3 = Strng
            ELSE
                Strng = "{" + Strng + "}"
                ERROR 92
            END IF
    END SELECT
END SUB

' process a number
SUB ParseNumeric (Temp#)
    SELECT CASE RIGHT$(UCASE$(Strng), 1) ' compare character after number
        CASE "Q" ' perfect number suffix
            FOR Digit = 1 TO LEN(Strng) - 1
                OutX$ = UCASE$(MID$(Strng, Digit, 1))
                SELECT CASE OutX$
                    CASE "0" TO "9"
                        ' nul
                    CASE ELSE
                        ERROR 131
                END SELECT
            NEXT
            Temp# = CDBL(VAL(LEFT$(Strng, LEN(Strng) - 1)))
            Perfect# = INT(Temp#)
            SELECT CASE Perfect# ' x = 1,2,4,6,12,16,18,30
                CASE 1#
                    X# = 1#
                CASE 2#
                    X# = 2#
                CASE 3#
                    X# = 4#
                CASE 4#
                    X# = 6#
                CASE 5#
                    X# = 12#
                CASE 6#
                    X# = 16#
                CASE 7#
                    X# = 18#
                CASE ELSE
                    ERROR 131
            END SELECT
            ' equation for perfect number
            Temp# = 2 ^ X# * (2 ^ (X# + 1) - 1)
        CASE "P" ' prime number suffix
            FOR Digit = 1 TO LEN(Strng) - 1
                OutX$ = UCASE$(MID$(Strng, Digit, 1))
                SELECT CASE OutX$
                    CASE "0" TO "9"
                        ' nul
                    CASE ELSE
                        ERROR 131
                END SELECT
            NEXT
            Temp# = CDBL(VAL(LEFT$(Strng, LEN(Strng) - 1)))
            PrimeNumber# = INT(Temp#)
            Prime# = 1
            IF PrimeNumber# > False THEN
                PrimeCounter# = False
                DO
                    Prime# = Prime# + 1
                    PrimeFlag = False
                    FOR Factor# = 2 TO INT(SQR(Prime#))
                        IF Prime# / Factor# = INT(Prime# / Factor#) THEN
                            PrimeFlag = True
                            EXIT FOR
                        END IF
                    NEXT
                    IF PrimeFlag = False THEN
                        PrimeCounter# = PrimeCounter# + 1
                    END IF
                    IF PrimeCounter# = PrimeNumber# THEN
                        EXIT DO
                    END IF
                LOOP
            END IF
            Temp# = Prime#
        CASE "F" ' factorial
            Temp2 = False
            Temp3 = LEN(Strng)
            DO
                IF UCASE$(MID$(Strng, Temp3, 1)) <> "F" THEN
                    EXIT DO
                END IF
                Temp2 = Temp2 + 1
                Temp3 = Temp3 - 1
            LOOP
            FOR Decimal.Digit = 1 TO Temp3
                OutX$ = UCASE$(MID$(Strng, Decimal.Digit, 1))
                SELECT CASE OutX$
                    CASE "0" TO "9"
                        ' nul
                    CASE ELSE
                        ERROR 132
                END SELECT
            NEXT
            Temp4# = VAL(LEFT$(Strng, Temp3))
            FOR Number = 1 TO Temp2
                Temp# = 1#
                FOR Factorial# = 2# TO Temp4#
                    Temp# = Temp# * Factorial#
                NEXT
                Temp4# = Temp#
            NEXT
        CASE "H" ' hexidecimal suffix
            Temp# = False
            HexPower = False
            FOR HexDigit = LEN(Strng) - 1 TO 1 STEP -1
                OutX$ = UCASE$(MID$(Strng, HexDigit, 1))
                SELECT CASE OutX$
                    CASE "0" TO "9", "A" TO "F"
                        HexValue = VAL("&H" + OutX$)
                        Temp# = Temp# + HexValue * 16 ^ HexPower
                        HexPower = HexPower + 1
                    CASE ELSE
                        ERROR 127
                END SELECT
            NEXT
        CASE "O" ' octal suffix
            Temp# = False
            OctalPower = False
            FOR OctalDigit = LEN(Strng) - 1 TO 1 STEP -1
                OutX$ = MID$(Strng, OctalDigit, 1)
                IF OutX$ >= "0" AND OutX$ <= "7" THEN
                    OctalValue = VAL(OutX$)
                    Temp# = Temp# + OctalValue * 8 ^ OctalPower
                    OctalPower = OctalPower + 1
                ELSE
                    ERROR 128
                END IF
            NEXT
        CASE "B" ' binary suffix
            Temp# = False
            BinaryPower = False
            FOR BinaryDigit = LEN(Strng) - 1 TO 1 STEP -1
                OutX$ = MID$(Strng, BinaryDigit, 1)
                SELECT CASE OutX$
                    CASE "0"
                        ' nul
                    CASE "1"
                        Temp# = Temp# + 2 ^ BinaryPower
                    CASE ELSE
                        ERROR 129
                END SELECT
                BinaryPower = BinaryPower + 1
            NEXT
        CASE "0" TO "9", "D", "E" ' decimal/exponent suffix
            Decimal = False
            Exponent = False
            Number$ = Strng
            StartToken:
            FOR DecimalDigit = 1 TO LEN(Number$)
                OutX$ = UCASE$(MID$(Number$, DecimalDigit, 1))
                SELECT CASE OutX$
                    CASE "0" TO "9", "-", "+"
                        ' nul
                    CASE "D", "E"
                        IF Exponent THEN
                            ERROR 140
                        END IF
                        Exponent = True
                        Exponent$ = UCASE$(RIGHT$(Number$, 1))
                        IF Exponent$ = "D" OR Exponent$ = "E" THEN
                            IF MID$(Out2, TokenIndex, 1) = " " THEN
                                TokenIndex = TokenIndex + 1
                            END IF
                            ' concatenate pre-parsed tokens into exponent
                            Unary$ = MID$(Out2, TokenIndex, 1)
                            IF Unary$ = "+" OR Unary$ = "-" THEN
                                Var$ = LEFT$(Out2, TokenIndex - 1)
                                CALL GetToken
                                VarX$ = Var$ + Strng
                                IF INSTR(VarX$, "--") THEN
                                    ERROR 142
                                END IF
                                IF INSTR(VarX$, "++") THEN
                                    ERROR 142
                                END IF
                                Out2 = Var$ + Strng + MID$(Out2, TokenIndex)
                                CALL GetToken
                                IF Strng = Nul THEN
                                    ERROR 141
                                END IF
                                Number$ = Number$ + Unary$ + Strng
                                IF Strng = "-" OR Strng = "+" THEN
                                    ERROR 142
                                END IF
                                IF INSTR(Strng, ".") THEN
                                    ERROR 143
                                END IF
                                ' remove pre-parsed leading unary signs
                                DO
                                    IF LEFT$(Number$, 1) = "-" THEN
                                        Number$ = MID$(Number$, 2)
                                    ELSE
                                        IF LEFT$(Number$, 1) = "+" THEN
                                            Number$ = MID$(Number$, 2)
                                        ELSE
                                            EXIT DO
                                        END IF
                                    END IF
                                LOOP
                                Decimal = False
                                Exponent = False
                                GOTO StartToken
                            ELSE
                                ERROR 142
                            END IF
                        END IF
                    CASE "."
                        IF Exponent THEN
                            ERROR 143
                        END IF
                        IF Decimal THEN
                            ERROR 143
                        END IF
                        Decimal = True
                    CASE ELSE
                        ERROR 130
                END SELECT
            NEXT
            Temp# = CDBL(VAL(Number$))
        CASE ELSE
            ERROR 131
    END SELECT
    CALL GetToken
    LastToken = True
END SUB

' parse string in quotes
SUB ParseQuoted
    Out3 = Nul
    DO UNTIL MID$(Out2, TokenIndex, 1) = Quote
        Out3 = Out3 + MID$(Out2, TokenIndex, 1)
        TokenIndex = TokenIndex + 1
        IF TokenIndex > LEN(Out2) THEN
            ERROR 133
            EXIT DO
        END IF
    LOOP
    CALL GetToken
    CALL GetToken
    LastToken = False
END SUB

' logical parser
SUB Parse1 (Temp#)
    CALL Parse2(Temp#) ' get next operator precedence
    TokenParsed$ = Strng ' store token
    ' process token
    DO
        SELECT CASE TokenParsed$
            CASE "|", "&", "~", "?", ":", "#", "@", "`"
                ' Nul
            CASE ELSE
                EXIT DO
        END SELECT
        TokenStored$ = Out3
        CALL GetToken ' read next token
        CALL Parse2(Temp2#) ' get next operator
        Out4 = Out3 ' reset current string
        Out3 = TokenStored$ ' restore previous string
        CALL Arith(TokenParsed$, Temp#, Temp2#) ' calculate expression
        TokenParsed$ = Strng ' store next token
    LOOP
END SUB

' relational parser
SUB Parse2 (Temp#)
    CALL Parse3(Temp#) ' get next operator precedence
    TokenParsed$ = Strng ' store token
    ' process token
    DO
        SELECT CASE TokenParsed$
            CASE "<", ">", "=", ">=", "<=", "<>", "=="
                ' Nul
            CASE ELSE
                EXIT DO
        END SELECT
        TokenStored$ = Out3 ' store current string
        CALL GetToken ' read next token
        CALL Parse3(Temp2#) ' get next operator
        Out4 = Out3 ' reset current string
        Out3 = TokenStored$ ' restore previous string
        CALL Arith(TokenParsed$, Temp#, Temp2#) ' calculate expression
        TokenParsed$ = Strng ' store next token
    LOOP
END SUB

' addition/subtraction parser
SUB Parse3 (Temp#)
    CALL Parse4(Temp#) ' get next operator precedence
    TokenParsed$ = Strng ' store token
    ' process token
    DO
        SELECT CASE TokenParsed$
            CASE "+", "-"
                ' Nul
            CASE ELSE
                EXIT DO
        END SELECT
        TokenStored$ = Out3
        CALL GetToken ' read next token
        CALL Parse4(Temp2#) ' get next operator
        Out4 = Out3
        Out3 = TokenStored$
        CALL Arith(TokenParsed$, Temp#, Temp2#) ' calculate expression
        TokenParsed$ = Strng ' store next token
    LOOP
END SUB

' modulo parser
SUB Parse4 (Temp#)
    CALL Parse5(Temp#) ' get next operator precedence
    TokenParsed$ = Strng ' store token
    ' process token
    DO
        SELECT CASE TokenParsed$
            CASE "%"
                ' Nul
            CASE ELSE
                EXIT DO
        END SELECT
        TokenStored$ = Out3
        CALL GetToken ' read next token
        CALL Parse5(Temp2#) ' get next operator
        Out4 = Out3
        Out3 = TokenStored$
        CALL Arith(TokenParsed$, Temp#, Temp2#) ' calculate expression
        TokenParsed$ = Strng ' store next token
    LOOP
END SUB

' integer division parser
SUB Parse5 (Temp#)
    CALL Parse6(Temp#) ' get next operator precedence
    TokenParsed$ = Strng ' store token
    ' process token
    DO
        SELECT CASE TokenParsed$
            CASE "\"
                ' Nul
            CASE ELSE
                EXIT DO
        END SELECT
        TokenStored$ = Out3
        CALL GetToken ' read next token
        CALL Parse6(Temp2#) ' get next operator
        Out4 = Out3
        Out3 = TokenStored$
        CALL Arith(TokenParsed$, Temp#, Temp2#) ' calculate expression
        TokenParsed$ = Strng ' store next token
    LOOP
END SUB

' multiplication/division parser
SUB Parse6 (Temp#)
    CALL Parse7(Temp#) ' get next operator precedence
    TokenParsed$ = Strng ' store token
    ' process token
    DO
        SELECT CASE TokenParsed$
            CASE "*", "/"
                ' Nul
            CASE ELSE
                EXIT DO
        END SELECT
        TokenStored$ = Out3
        CALL GetToken ' read next token
        CALL Parse7(Temp2#) ' get next operator
        Out4 = Out3
        Out3 = TokenStored$
        CALL Arith(TokenParsed$, Temp#, Temp2#) ' calculate expression
        TokenParsed$ = Strng ' store next token
    LOOP
END SUB

' power parser
SUB Parse7 (Temp#)
    CALL Parse7a(Temp#) ' get next operator precedence
    TokenParsed$ = Strng ' store token
    ' process token
    DO
        SELECT CASE TokenParsed$
            CASE "^"
                ' Nul
            CASE ELSE
                EXIT DO
        END SELECT
        TokenStored$ = Out3
        CALL GetToken ' read next token
        CALL Parse7a(Temp2#) ' get next operator
        Out4 = Out3
        Out3 = TokenStored$
        CALL Arith(TokenParsed$, Temp#, Temp2#) ' calculate expression
        TokenParsed$ = Strng ' store next token
    LOOP
END SUB

' dual-unary parser
SUB Parse7a (Temp#)
    CALL Parse8(Temp#) ' get next operator precedence
    TokenParsed$ = Strng ' store token
    ' process token
    DO
        SELECT CASE TokenParsed$
            CASE "<<", ">>", "--", "++", "**", "//", "||", "##", "^^"
                ' Nul
            CASE ELSE
                EXIT DO
        END SELECT
        TokenStored$ = Out3 ' store current token
        CALL GetToken ' read next token
        ' CALL Parse8(Temp2#) ' get next operator
        Out4 = Out3 ' reset current string
        Out3 = TokenStored$ ' restore previous string
        CALL Arith(TokenParsed$, Temp#, Temp2#) ' calculate expression
        TokenParsed$ = Strng ' store next token
    LOOP
END SUB

' not/unary plus/unary negative parser
SUB Parse8 (Temp#)
    TokenNegate$ = Nul ' reset token storage
    TokenParsed$ = Strng ' store token
    ' process token
    DO
        SELECT CASE TokenParsed$
            CASE "!", "-", "+", "--", "++"
                ' Nul
            CASE ELSE
                EXIT DO
        END SELECT
        CALL GetToken ' read next token
        TokenNegate$ = TokenNegate$ + TokenParsed$
        TokenParsed$ = Strng ' store token
    LOOP
    CALL Parse9(Temp#) ' get next operator

    ' process the combined operators in reverse
    FOR TokenType = LEN(TokenNegate$) TO 1 STEP -1
        SELECT CASE MID$(TokenNegate$, TokenType, 1) ' get previous token
            CASE "+"
                ' nul calculation for unary plus
            CASE "-"
                Temp# = -Temp# ' perform negate
            CASE "!" ' not
                Temp# = NOT Temp# ' perform not calculation
        END SELECT
    NEXT
END SUB

' string/numeric expression parser,
' routine returns calculated expression string/value,
' calls Parse1 recursively for values inside parenthesis/functions.
SUB Parse9 (Temp#)
    SELECT CASE Token ' determine token type
        CASE 0 ' no terminating token
            IF LastToken = 3 THEN
                IF AllowExtra = False THEN
                    Strng = "<extra token>"
                    ERROR 92
                END IF
            ELSE
                IF Strng = Nul THEN
                    Strng = "<missing token>"
                ELSE
                    Strng = "<" + Strng + ">"
                END IF
                ERROR 92
            END IF
            LastToken = False
        CASE 1 ' token is symbol
            TokenParsed$ = Strng
            SELECT CASE TokenParsed$
                CASE ",", ";" ' separaters
                    Token = False
                    LastToken = 3
                CASE Quote ' parse string in quotes
                    CALL ParseQuoted
                    Quotes = True
                CASE "(" ' calculate opening parenthesis
                    CALL GetToken ' read next token value inside parenthesis
                    IF Strng = ")" THEN
                        Strng = "<empty closing token>"
                        ERROR 92
                    END IF
                    IF Strng <> ")" THEN
                        DO ' calculate value
                            CALL Parse1(Temp#) ' recursively call parse entry
                        LOOP UNTIL Strng = ")" OR Token = False ' check closing parenthesis
                    END IF
                    IF Token = False THEN
                        Strng = "<missing closing token>"
                        ERROR 92
                    END IF
                    CALL GetToken ' read next token after parenthesis
                CASE "["
                    CALL GetToken
                    IF Strng = "]" THEN
                        Strng = "<empty closing token>"
                        ERROR 92
                    END IF
                    IF Strng <> "]" THEN
                        DO
                            CALL Parse1(Temp#) ' recursively call parse entry
                        LOOP UNTIL Strng = "]" OR Token = False ' check closing parenthesis
                    END IF
                    IF Token = False THEN
                        Strng = "<missing closing token>"
                        ERROR 92
                    END IF
                    CALL GetToken ' read next token after parenthesis
                CASE "{"
                    CALL GetToken
                    IF Strng = "}" THEN
                        Strng = "<empty closing token>"
                        ERROR 92
                    END IF
                    IF Strng <> "}" THEN
                        DO
                            CALL Parse1(Temp#) ' recursively call parse entry
                        LOOP UNTIL Strng = "}" OR Token = False ' check closing parenthesis
                    END IF
                    IF Token = False THEN
                        Strng = "<missing closing token>"
                        ERROR 92
                    END IF
                    CALL GetToken ' read next token after parenthesis
                CASE ")", "]", "}" ' check token is unmatched parenthesis
                    IF AllowExtra <= False THEN
                        Strng = "<extra closing token>"
                        ERROR 92
                    END IF
            END SELECT
        CASE 2 ' token is numeric value
            CALL ParseNumeric(Temp#)
        CASE 3 ' token type is alphabetic
            SELECT CASE LEN(Strng) ' check token length
                CASE 1
                    ' parse the token
                    CALL ParseAlphabetic1(Temp#)
                CASE 2
                    SELECT CASE UCASE$(Strng)
                        ' special tokens
                        CASE "AS"
                            CALL GetToken
                            EXIT SUB
                        CASE "TO"
                            CALL GetToken
                            CALL Parse1(Temp4#)
                            FinishFor = Temp4#
                            EXIT SUB
                    END SELECT
                    ' parse the token
                    CALL ParseAlphabetic2(Temp#)
                CASE ELSE
                    SELECT CASE UCASE$(Strng)
                        ' printing tokens
                        CASE "SPC"
                            IF Printing = False THEN
                                ERROR 92
                            END IF
                            IF PrinterLF = -2 THEN ' write function
                                ERROR 92
                            END IF
                            CALL GetToken3
                            CALL GetToken
                            CALL Parse1(Temp#)
                            SELECT CASE PrinterLF
                                CASE -1
                                    IF Temp# < 0# THEN
                                        ERROR 161
                                    ELSE
                                        LPRINT SPACE$(Temp#);
                                    END IF
                                CASE 1
                                    IF Temp# < 0# THEN
                                        ERROR 167
                                    ELSE
                                        PRINT SPC(Temp#);
                                    END IF
                            END SELECT
                            CALL GetToken
                            IF PrinterLF THEN
                                CALL GetToken
                                CALL Parse1(Temp#)
                            END IF
                            EXIT SUB
                        CASE "TAB"
                            IF Printing = False THEN
                                ERROR 92
                            END IF
                            IF PrinterLF = -2 THEN ' write function
                                ERROR 92
                            END IF
                            CALL GetToken3
                            CALL GetToken
                            CALL Parse1(Temp#)
                            SELECT CASE PrinterLF
                                CASE -1
                                    IF Temp# < 0# THEN
                                        ERROR 161
                                    ELSE
                                        LPRINT TAB(Temp#);
                                    END IF
                                CASE 1
                                    IF Temp# < 0# THEN
                                        ERROR 167
                                    ELSE
                                        PRINT TAB(Temp#);
                                    END IF
                            END SELECT
                            CALL GetToken
                            IF PrinterLF THEN
                                CALL GetToken
                                CALL Parse1(Temp#)
                            END IF
                            EXIT SUB

                            ' special tokens
                        CASE "THEN"
                            CALL GetToken
                            EXIT SUB
                        CASE "STEP"
                            CALL GetToken
                            CALL Parse1(Temp4#)
                            StepTo = Temp4#
                            EXIT SUB
                        CASE "EXCEPT"
                            CALL GetToken
                            CALL Parse1(Temp4#)
                            ExceptStep = Temp4#
                            ExceptStepIs = True
                            EXIT SUB
                        CASE "UNLESS"
                            CALL GetToken
                            CALL Parse1(Temp4#)
                            UnlessBranch = True
                            UnlessValue = Temp4#
                            EXIT SUB
                    END SELECT
                    ' parse the token
                    CALL ParseAlphabetic3(Temp#)
            END SELECT
            ' parse the last token
            ' after any alphabetic token
            ' except the special tokens above.
            CALL GetToken
    END SELECT
END SUB

' parses data statements.
SUB ReadDataElement (MoreData)
    MoreData = False
    VarX = DataLine
    StoredOut2$ = Out2
    StoredTokenIndex = TokenIndex
    DO
        Out2 = Program$(VarX)
        Out2 = STRIM$(Out2)
        Out2 = UCASE$(Out2)
        IF LEFT$(Out2, 4) <> "DATA" THEN
            Var = DataLine
            Var2 = False
            DO
                IF Var >= LastLine THEN
                    EXIT DO
                END IF
                Var = Var + 1
                Strng2$ = Program$(Var)
                Strng2$ = STRIM$(Strng2$)
                Strng2$ = UCASE$(Strng2$)
                IF LEFT$(Strng2$, 4) = "DATA" THEN
                    DataLine = Var
                    Var2 = True
                    EXIT DO
                END IF
            LOOP
            IF Var2 = False THEN
                MoreData = True
                EXIT SUB
            END IF
            DataNumber = False
        END IF
        Out2 = Program$(DataLine)
        Out2 = STRIM$(Out2)
        Out2 = MID$(Out2, 5)
        Out2 = XTRIM$(Out2, True)
        CALL TrimComment

        ' append trailing data seperator
        Out2 = Out2 + ","

        DataCount = False
        TokenIndex = 1
        DO
            LastToken = False
            CALL GetToken
            SELECT CASE Strng
                CASE ",", ";"
                    DataValue = 0#
                    Out3 = Nul
                CASE ELSE
                    ' allow equations in DATA elements!?
                    CALL Parse1(DataValue)

                    ' next token should be data terminator
                    SELECT CASE Strng
                        CASE Quote
                            ERROR 133
                            EXIT SUB
                        CASE ",", ";"
                            Eat$ = Nul
                        CASE ELSE
                            ERROR 66
                            EXIT SUB
                    END SELECT
            END SELECT
            IF DataCount = DataNumber THEN
                DataNumber = DataNumber + 1
                Out2 = StoredOut2$
                TokenIndex = StoredTokenIndex
                EXIT SUB
            END IF
            IF TokenIndex > LEN(Out2) THEN
                EXIT DO
            END IF
            DataCount = DataCount + 1
        LOOP
        VarX = VarX + 1
        DataNumber = False
    LOOP
END SUB

' parses filename and returns drive\path\filename.sic
SUB Concatenate (ProgramFile$)
    ProgramFile$ = STRIM$(ProgramFile$)
    ProgramFile$ = LCASE$(ProgramFile$)
    ProgramDrive$ = Nul
    ProgramPath$ = Nul
    IF MID$(ProgramFile$, 2, 1) = ":" THEN
        ProgramDrive$ = LEFT$(ProgramFile$, 2)
        ProgramFile$ = MID$(ProgramFile$, 3)
    END IF
    FOR Var = LEN(ProgramFile$) TO 1 STEP -1
        IF MID$(ProgramFile$, Var, 1) = "\" THEN
            ProgramPath$ = LEFT$(ProgramFile$, Var)
            ProgramFile$ = MID$(ProgramFile$, Var + 1)
            EXIT FOR
        END IF
    NEXT
    IF RIGHT$(ProgramFile$, 4) = ".sic" THEN
        ProgramFile$ = LEFT$(ProgramFile$, LEN(ProgramFile$) - 4)
    END IF
    ProgramFile$ = ProgramDrive$ + ProgramPath$ + ProgramFile$ + ".sic"
END SUB

' check validity of program
SUB AnalyzeProgram (Var1, Var2, Var1$)
    Var2 = 0
    CALL CountLines(LastLine)
    IF Var1 = -1 THEN
        COLOR Yellow, Black
        PRINT "Analyzing Program: "; ProgramName
        COLOR White, Black
        PRINT "Pass 1: counting matching structures."
    END IF

    FOR ProgramLine = 1 TO LastLine
        Out2$ = Program(ProgramLine)
        Out2$ = STRIM$(Out2$)
        IF LEN(Out2$) THEN
            Temp1$ = STRIM$(Out2$)
            Temp1$ = UCASE$(Temp1$)
        END IF
        IF LEFT$(Temp1$, 4) = "THEN" THEN
            Var2 = -1
            Var1$ = "Incorrect structure"
            IF Var1 = -1 THEN
                PRINT "Analyze error, pass 1: Incorrect structure : Line:" + STR$(ProgramLine)
            END IF
            EXIT SUB
        END IF
        IF LEFT$(Temp1$, 4) = "STEP" THEN
            Var2 = -1
            Var1$ = "Incorrect structure"
            IF Var1 = -1 THEN
                PRINT "Analyze error, pass 1: Incorrect structure : Line:" + STR$(ProgramLine)
            END IF
            EXIT SUB
        END IF
        IF LEFT$(Temp1$, 6) = "UNLESS" THEN
            Var2 = -1
            Var1$ = "Incorrect structure"
            IF Var1 = -1 THEN
                PRINT "Analyze error, pass 1: Incorrect structure : Line:" + STR$(ProgramLine)
            END IF
            EXIT SUB
        END IF
        IF LEFT$(Temp1$, 6) = "EXCEPT" THEN
            Var2 = -1
            Var1$ = "Incorrect structure"
            IF Var1 = -1 THEN
                PRINT "Analyze error, pass 1: Incorrect structure : Line:" + STR$(ProgramLine)
            END IF
            EXIT SUB
        END IF
    NEXT

    RESTORE AnalyzeData1
    FOR DataCount = 1 TO 8
        READ StartStructure$, StopStructure$
        NestedCount = False
        FOR ProgramLine = 1 TO LastLine
            Out2$ = Program(ProgramLine)
            Out2$ = STRIM$(Out2$)
            IF LEN(Out2$) THEN
                Temp1$ = STRIM$(Out2$)
                Temp1$ = UCASE$(Temp1$)
                CountData1 = False
                IF LEFT$(Temp1$, LEN(StartStructure$)) = StartStructure$ THEN
                    CountData1 = True
                END IF
                IF StartStructure$ = "FOR" THEN
                    IF LEFT$(Temp1$, 5) = "FORIF" THEN
                        CountData1 = False
                    END IF
                END IF
                IF CountData1 THEN
                    NestedCount = NestedCount + 1
                END IF
                IF StartStructure$ = "IF" THEN
                    IF LEFT$(Temp1$, 6) = "END IF" THEN
                        NestedCount = NestedCount - 1
                        IF NestedCount < False THEN
                            Var2 = -1
                            Var1$ = "Incomplete " + StartStructure$
                            IF Var1 = -1 THEN
                                PRINT "Analyze error, pass 1: Incomplete " + StartStructure$ + ": Line:" + STR$(ProgramLine)
                            END IF
                            EXIT SUB
                        END IF
                    END IF
                END IF
                IF StopStructure$ = "LOOP" THEN
                    IF LEFT$(Temp1$, 6) <> "LOOPIF" THEN
                        Temp1$ = LEFT$(Temp1$, 4)
                    END IF
                END IF
                IF StopStructure$ = "NEXT" THEN
                    IF LEFT$(Temp1$, 6) <> "NEXTIF" THEN
                        Temp1$ = LEFT$(Temp1$, 4)
                    END IF
                END IF
                IF StopStructure$ = "END SELECT" THEN
                    IF LEFT$(Temp1$, 12) <> "END SELECTIF" THEN
                        Temp1$ = LEFT$(Temp1$, 10)
                    END IF
                END IF
                IF Temp1$ = StopStructure$ THEN
                    NestedCount = NestedCount - 1
                    IF NestedCount < False THEN
                        Var2 = -1
                        Var1$ = "Incomplete " + StartStructure$
                        IF Var1 = -1 THEN
                            PRINT "Analyze error, pass 1: Incomplete " + StartStructure$ + ": Line:" + STR$(ProgramLine)
                        END IF
                        EXIT SUB
                    END IF
                END IF
            END IF
        NEXT
    NEXT
    IF Var1 = -1 THEN
        PRINT "Pass 2: counting matching imbedded structures."
    END IF
    RESTORE AnalyzeData2
    FOR DataCount = 1 TO 3
        READ StartStructure$, StopStructure$, Imbedded1$, Imbedded2$
        NestedCount = False
        FOR ProgramLine = 1 TO LastLine
            Out2$ = Program(ProgramLine)
            Out2$ = STRIM$(Out2$)
            IF LEN(Out2$) THEN
                Temp1$ = STRIM$(Out2$)
                Temp1$ = UCASE$(Temp1$)
                IF LEFT$(Temp1$, LEN(StartStructure$)) = StartStructure$ THEN
                    NestedCount = NestedCount + 1
                END IF
                IF LEFT$(Temp1$, LEN(Imbedded1$)) = Imbedded1$ THEN
                    NestedCount = NestedCount - 1
                    IF NestedCount < False THEN
                        Var2 = -1
                        Var1$ = "Incomplete " + StartStructure$
                        IF Var1 = -1 THEN
                            PRINT "Analyze error, pass 2: Incomplete " + StartStructure$ + ": Line:" + STR$(ProgramLine)
                        END IF
                        EXIT SUB
                    END IF
                    NestedCount = NestedCount + 1
                ELSE
                    Temp2$ = Temp1$
                    IF Imbedded2$ <> "ELSEIF" THEN
                        IF LEFT$(Temp1$, LEN(Imbedded2$)) = Imbedded2$ THEN
                            Imbedded3 = INSTR(Temp1$, " ")
                            IF Imbedded3 = False THEN
                                Var2 = -1
                                Var1$ = "Bad " + Imbedded2$
                                IF Var1 = -1 THEN
                                    PRINT "Analyze error, pass 2: Bad " + Imbedded2$ + ": Line:" + STR$(ProgramLine)
                                END IF
                                EXIT SUB
                            END IF
                            Temp2$ = LEFT$(Temp1$, Imbedded3 - 1)
                        END IF
                    END IF
                    IF Temp2$ = Imbedded2$ THEN
                        NestedCount = NestedCount - 1
                        IF NestedCount < False THEN
                            Var2 = -1
                            Var1$ = "Incomplete " + StartStructure$
                            IF Var1 = -1 THEN
                                PRINT "Analyze error, pass 2: Incomplete " + StartStructure$ + ": Line:" + STR$(ProgramLine)
                            END IF
                            EXIT SUB
                        END IF
                        NestedCount = NestedCount + 1
                    END IF
                END IF
                IF StartStructure$ = "IF" THEN
                    IF LEFT$(Temp1$, 6) = "END IF" THEN
                        NestedCount = NestedCount - 1
                        IF NestedCount < False THEN
                            Var2 = -1
                            Var1$ = "Incomplete " + StartStructure$
                            IF Var1 = -1 THEN
                                PRINT "Analyze error, pass 2: Incomplete " + StartStructure$ + ": Line:" + STR$(ProgramLine)
                            END IF
                            EXIT SUB
                        END IF
                    END IF
                END IF
                IF Temp1$ = StopStructure$ THEN
                    NestedCount = NestedCount - 1
                    IF NestedCount < False THEN
                        Var2 = -1
                        Var1$ = "Incomplete " + StartStructure$
                        IF Var1 = -1 THEN
                            PRINT "Analyze error, pass 2: Incomplete " + StartStructure$ + ": Line:" + STR$(ProgramLine)
                        END IF
                        EXIT SUB
                    END IF
                END IF
            END IF
        NEXT
    NEXT
    IF Var1 = -1 THEN
        PRINT "Pass 3: multipass structure match."
    END IF
    RESTORE AnalyzeData1
    FOR DataCount = 1 TO 8
        READ StartStructure$, StopStructure$
        FOR ProgramLine = 1 TO LastLine
            Out2$ = Program(ProgramLine)
            Out2$ = STRIM$(Out2$)
            IF LEN(Out2$) THEN
                Temp1$ = STRIM$(Out2$)
                Temp1$ = UCASE$(Temp1$)
                CountData1 = False
                IF LEFT$(Temp1$, LEN(StartStructure$)) = StartStructure$ THEN
                    CountData1 = True
                END IF
                IF StartStructure$ = "FOR" THEN
                    IF LEFT$(Temp1$, 5) = "FORIF" THEN
                        CountData1 = False
                    END IF
                END IF
                IF CountData1 THEN
                    NestedCount = 1
                    FOR NestedLines = ProgramLine + 1 TO LastLine
                        Temp2$ = Program(NestedLines)
                        Temp2$ = STRIM$(Temp2$)
                        IF LEN(Temp2$) THEN
                            Temp2$ = STRIM$(Temp2$)
                            Temp2$ = UCASE$(Temp2$)
                            CountData2 = False
                            IF LEFT$(Temp2$, LEN(StartStructure$)) = StartStructure$ THEN
                                CountData2 = True
                            END IF
                            IF StartStructure$ = "FOR" THEN
                                IF LEFT$(Temp2$, 5) = "FORIF" THEN
                                    CountData2 = False
                                END IF
                            END IF
                            IF CountData2 THEN
                                NestedCount = NestedCount + 1
                            END IF
                            IF StopStructure$ = "LOOP" THEN
                                IF LEFT$(Temp2$, 6) <> "LOOPIF" THEN
                                    Temp2$ = LEFT$(Temp2$, 4)
                                END IF
                            END IF
                            IF StopStructure$ = "NEXT" THEN
                                IF LEFT$(Temp2$, 6) <> "NEXTIF" THEN
                                    Temp2$ = LEFT$(Temp2$, 4)
                                END IF
                            END IF
                            IF StopStructure$ = "END SELECT" THEN
                                IF LEFT$(Temp1$, 12) <> "END SELECTIF" THEN
                                    Temp1$ = LEFT$(Temp1$, 10)
                                END IF
                            END IF
                            IF Temp2$ = StopStructure$ THEN
                                NestedCount = NestedCount - 1
                                IF NestedCount = False THEN
                                    EXIT FOR
                                END IF
                            END IF
                            IF StartStructure$ = "IF" THEN
                                IF LEFT$(Temp2$, 6) = "END IF" THEN
                                    NestedCount = NestedCount - 1
                                    IF NestedCount = False THEN
                                        EXIT FOR
                                    END IF
                                END IF
                            END IF
                        END IF
                    NEXT
                    IF NestedCount <> False THEN
                        Var2 = -1
                        Var1$ = "Mismatched " + StartStructure$
                        IF Var1 = -1 THEN
                            PRINT "Analyze error, pass 3: Mismatched " + StartStructure$ + ": Line:" + STR$(ProgramLine)
                        END IF
                        EXIT SUB
                    END IF
                END IF
            END IF
        NEXT
    NEXT
    IF Var1 = -1 THEN
        PRINT "Pass 4: multipass imbedded struture match."
    END IF
    RESTORE AnalyzeData2
    FOR DataCount = 1 TO 3
        READ StartStructure$, StopStructure$, Imbedded1$, Imbedded2$
        FOR ProgramLine = 1 TO LastLine
            Out2$ = Program(ProgramLine)
            Out2$ = STRIM$(Out2$)
            IF LEN(Out2$) THEN
                Temp1$ = STRIM$(Out2$)
                Temp1$ = UCASE$(Temp1$)
                IF LEFT$(Temp1$, LEN(StartStructure$)) = StartStructure$ THEN
                    TotalNested1 = 1
                    TotalNested2 = False
                    NestedCount1 = 1
                    NestedCount2 = False
                    FOR NestedLines = ProgramLine + 1 TO LastLine
                        Temp2$ = Program(NestedLines)
                        Temp2$ = STRIM$(Temp2$)
                        IF LEN(Temp2$) THEN
                            Temp2$ = STRIM$(Temp2$)
                            Temp2$ = UCASE$(Temp2$)
                            IF LEFT$(Temp2$, LEN(StartStructure$)) = StartStructure$ THEN
                                TotalNested1 = TotalNested1 + 1
                                NestedCount1 = NestedCount1 + 1
                            END IF
                            IF Temp2$ = StopStructure$ THEN
                                TotalNested2 = TotalNested2 - 1
                                NestedCount1 = NestedCount1 - 1
                                IF NestedCount1 = False THEN
                                    EXIT FOR
                                END IF
                            END IF
                            IF StartStructure$ = "IF" THEN
                                IF LEFT$(Temp2$, 6) = "END IF" THEN
                                    NestedCount1 = NestedCount1 - 1
                                    IF NestedCount1 = False THEN
                                        EXIT FOR
                                    END IF
                                END IF
                            END IF
                            IF LEFT$(Temp2$, LEN(Imbedded1$)) = Imbedded1$ THEN
                                NestedCount2 = NestedCount2 + 1
                                IF NestedCount2 > NestedCount1 THEN
                                    Var2 = -1
                                    Var1$ = "Mismatched " + StartStructure$
                                    IF Var1 = -1 THEN
                                        PRINT "Analyze error, pass 4: Mismatched " + StartStructure$ + ": Line:" + STR$(ProgramLine)
                                    END IF
                                    EXIT SUB
                                END IF
                                NestedCount2 = NestedCount2 - 1
                            ELSE
                                Temp3$ = Temp2$
                                IF Imbedded2$ <> "ELSEIF" THEN
                                    IF LEFT$(Temp2$, LEN(Imbedded2$)) = Imbedded2$ THEN
                                        Imbedded3 = INSTR(Temp2$, " ")
                                        IF Imbedded3 = False THEN
                                            Var2 = -1
                                            Var1$ = "Bad " + Imbedded2$
                                            IF Var1 = -1 THEN
                                                PRINT "Analyze error, pass 4: Bad " + Imbedded2$ + ": Line:" + STR$(ProgramLine)
                                            END IF
                                            EXIT SUB
                                        END IF
                                        Temp3$ = LEFT$(Temp2$, Imbedded3 - 1)
                                    END IF
                                END IF
                                IF Temp3$ = Imbedded2$ THEN
                                    NestedCount2 = NestedCount2 + 1
                                    IF NestedCount2 > NestedCount1 THEN
                                        Var2 = -1
                                        Var1$ = "Mismatched " + StartStructure$
                                        IF Var1 = -1 THEN
                                            PRINT "Analyze error, pass 4: Mismatched " + StartStructure$ + ": Line:" + STR$(ProgramLine)
                                        END IF
                                        EXIT SUB
                                    END IF
                                    NestedCount2 = NestedCount2 - 1
                                END IF
                            END IF
                        END IF
                    NEXT
                    IF TotalNested2 > TotalNested1 THEN
                        Var2 = -1
                        Var1$ = "Mismatched " + StartStructure$
                        IF Var1 = -1 THEN
                            PRINT "Analyze error, pass 4: Mismatched " + StartStructure$ + ": Line:" + STR$(ProgramLine)
                        END IF
                        EXIT SUB
                    END IF
                END IF
            END IF
        NEXT
    NEXT
    IF Var1 = -1 THEN
        PRINT "Pass 5: single pass imbedded control structure match."
    END IF
    RESTORE AnalyzeData3
    FOR DataCount = 1 TO 5
        READ StartStructure$, StopStructure$, Imbedded1$, Imbedded2$
        NestedCount = False
        FOR ProgramLine = 1 TO LastLine
            Out2$ = Program(ProgramLine)
            Out2$ = STRIM$(Out2$)
            IF LEN(Out2$) THEN
                Temp1$ = STRIM$(Out2$)
                Temp1$ = UCASE$(Temp1$)
                CountData1 = False
                IF LEFT$(Temp1$, LEN(StartStructure$)) = StartStructure$ THEN
                    CountData1 = True
                END IF
                IF StartStructure$ = "FOR" THEN
                    IF LEFT$(Temp1$, 5) = "FORIF" THEN
                        CountData1 = False
                    END IF
                END IF
                IF CountData1 THEN
                    NestedCount = NestedCount + 1
                END IF
                CountData2 = False
                IF LEFT$(Temp1$, LEN(StopStructure$)) = StopStructure$ THEN
                    CountData2 = True
                END IF
                IF StopStructure$ = "LOOP" THEN
                    IF LEFT$(Temp1$, 6) = "LOOPIF" THEN
                        CountData2 = False
                    END IF
                END IF
                IF StopStructure$ = "NEXT" THEN
                    IF LEFT$(Temp1$, 6) = "NEXTIF" THEN
                        CountData2 = False
                    END IF
                END IF
                IF CountData2 THEN
                    NestedCount = NestedCount - 1
                END IF
                IF LEFT$(Temp1$, LEN(Imbedded1$)) = Imbedded1$ THEN
                    IF NestedCount <= False THEN
                        Var2 = -1
                        Var1$ = "Badly nested " + StartStructure$
                        IF Var1 = -1 THEN
                            PRINT "Analyze error, pass 5: Badly nested " + StartStructure$ + ": Line:" + STR$(ProgramLine)
                        END IF
                        EXIT SUB
                    END IF
                END IF
                IF LEFT$(Temp1$, LEN(Imbedded2$)) = Imbedded2$ THEN
                    IF NestedCount <= False THEN
                        Var2 = -1
                        Var1$ = "Badly nested " + StartStructure$
                        IF Var1 = -1 THEN
                            PRINT "Analyze error, pass 5: Badly nested " + StartStructure$ + ": Line:" + STR$(ProgramLine)
                        END IF
                        EXIT SUB
                    END IF
                END IF
            END IF
        NEXT
    NEXT
    IF Var1 = -1 THEN
        COLOR Yellow, Black
        PRINT "Analysis completed. Program syntax correct."
    END IF
END SUB

' function to match case-sensitive substring with ?, * characters in substring
SUB InstrSUB1 (Var, Var1$, Var2$, VarQ)

    ' store case-sensitive string match variables
    IF VarQ THEN
        S2$ = Var1$
        S3$ = Var2$
    ELSE
        S2$ = LCASE$(Var1$)
        S3$ = LCASE$(Var2$)
    END IF

    ' check default instr
    IF INSTR(S2$, "*") = 0 THEN
        IF INSTR(S2$, "?") = 0 THEN
            Var = INSTR(S3$, S2$)
            EXIT SUB
        END IF
    END IF

    Var = -1 ' assume match

    ' see if S2$ matches in S3$ with substrings
    FOR S3 = 1 TO LEN(S3$)
        S1$ = MID$(S3$, S3)
        P1 = 1 ' pointer to S1$
        P2 = 1 ' pointer to S2$
        DO
            ' check match
            IF P2 > LEN(S2$) THEN
                EXIT SUB
            END IF

            ' check character in S2$ at P2
            V$ = MID$(S2$, P2, 1)
            SELECT CASE V$
                CASE "*" ' global character
                    ' scan to next char
                    IF P2 > LEN(S2$) THEN
                        EXIT DO
                    END IF
                    S4$ = MID$(S2$, P2 + 1, 1)
                    SELECT CASE S4$
                        CASE "*", "?"
                            P2 = P2 + 1
                        CASE ELSE
                            DO
                                IF MID$(S1$, P1, 1) = S4$ THEN
                                    EXIT DO
                                END IF
                                IF P1 >= LEN(S1$) THEN
                                    EXIT DO
                                END IF
                                P1 = P1 + 1
                            LOOP
                            P2 = P2 + 1
                    END SELECT
                CASE "?" ' wildcard character
                    P1 = P1 + 1
                    P2 = P2 + 1
                CASE ELSE ' ascii character
                    IF MID$(S1$, P1, 1) <> V$ THEN ' no match
                        EXIT DO
                    END IF
                    P1 = P1 + 1
                    P2 = P2 + 1
            END SELECT
        LOOP
    NEXT
    Var = 0 ' no match
END SUB

SUB Capitalize (Var3$)
    Var3$ = RTRIM$(LTRIM$(Var3$))
    IF Var3$ = Nul THEN
        EXIT SUB
    END IF
    MID$(Var3$, 1, 1) = UCASE$(MID$(Var3$, 1, 1))
    Var = INSTR(Var3$, " ")
    IF Var < LEN(Var3$) THEN
        DO WHILE Var
            MID$(Var3$, Var + 1, 1) = UCASE$(MID$(Var3$, Var + 1, 1))
            Var = INSTR(Var + 1, Var3$, " ")
        LOOP
    END IF
END SUB

' calculate byte suffix
SUB Suffix (Var#, Var3$)

    REM B  (Byte) = 00x - 0FFx (hexidecimal zero-based)
    REM KB (Kilobyte) = 1024 B
    REM MB (Megabyte) = 1024 KB (1 MB B)
    REM GB (Gigabyte) = 1024 MB
    REM TB (Terabyte) = 1024 GB (1 MB MB)
    REM PB (Petabyte) = 1024 TB
    REM EB (Exabyte) = 1024 PB (1 MB TB)
    REM ZB (Zettabyte) = 1024 EB
    REM YB (Yottabyte) = 1024 ZB (1 MB EB)

    ' check double
    VarX# = Var#
    s$ = STR$(VarX#)
    IF INSTR(s$, "D") THEN
        Var3$ = s$
        EXIT SUB
    END IF

    ' get sign
    IF VarX# < 0# THEN
        Sign = -1
        VarX# = ABS(VarX#)
    END IF

    ' calculate bytes
    TempA = False
    DO
        IF VarX# >= ByteDivisor THEN
            VarX# = VarX# / ByteDivisor
            TempA = TempA + 1
            IF TempA = 8 THEN
                EXIT DO
            END IF
        ELSE
            EXIT DO
        END IF
    LOOP

    ' calculate byte string
    Var3$ = FormatString$(VarX#)
    IF INSTR(Var3$, ".") THEN
        Var3$ = LEFT$(Var3$, INSTR(Var3$, ".") + 1)
    ELSE
        Var3$ = Var3$ + ".0"
    END IF

    ' calculate byte suffix
    Var$ = Nul
    IF TempA > 0 THEN
        Var$ = MID$("KMGTPEZY", TempA, 1)
    END IF
    Var3$ = Var3$ + " " + Var$ + "B"

    ' calculate byte sign
    IF Sign THEN
        Var3$ = "-" + Var3$
    END IF
END SUB

' trim trailing comment/underscore
SUB TrimComment
    IF LEN(Out2) THEN
        StartChar = 1
        DO
            QuoteStart = False
            FOR Temp = StartChar TO LEN(Out2)
                IF MID$(Out2, Temp, 1) = CHR$(34) THEN
                    QuoteStart = Temp
                    EXIT FOR
                END IF
            NEXT
            IF QuoteStart = False THEN
                EXIT DO
            END IF
            QuoteStop = False
            FOR Temp2 = QuoteStart + 1 TO LEN(Out2)
                IF MID$(Out2, Temp2, 1) = CHR$(34) THEN
                    QuoteStop = Temp2
                    EXIT FOR
                END IF
            NEXT
            IF QuoteStop = False THEN
                EXIT DO
            END IF
            StartChar = QuoteStop + 1
        LOOP
        FOR Temp = StartChar TO LEN(Out2)
            IF MID$(Out2, Temp, 1) = "'" THEN
                Out2 = LEFT$(Out2, Temp - 1)
                EXIT FOR
            END IF
        NEXT
        Out2 = STRIM$(Out2)
    END IF

    ' trim continuation character
    DO
        V$ = RIGHT$(Out2, 1)
        IF V$ = CHR$(9) OR V$ = CHR$(32) OR V$ = "_" THEN
            Out2 = LEFT$(Out2, LEN(Out2) - 1)
        ELSE
            EXIT DO
        END IF
    LOOP
END SUB

REM - end of the SIC64 experimental source for the QB64 compiler -

REM $Include: 'sxmath.bm'
REM $Include: 'sxript.bm'

