#               LIST_ON                                 : REM CHANGE TO COMMENT LINE IF NOT WANTED
#               XREF_ON                                 : REM CHANGE TO COMMENT LINE IF NOT WANTED
#               CONSTANT UBN~VERSION$      = "1.060202 RC0"
#               CONSTANT UBN_TITLE$        = "Urbane XUBN~VERSION$  - Tandy Color Computer 3 Disk Extended Color Basic Preprocessor."
'               Original Left Hello A. Nani Mouse Inx.

#               CONSTANT IN_FILE$          = "UBN_IN.TXT"
#               CONSTANT OUT_FILE$         = "UBN_OUT.TXT"
#               CONSTANT LST_FILE$         = "UBN_LST.TXT"
#               CONSTANT XRF_FILE$         = "UBN_XRF.TXT"

#               CONSTANT NUM_M1            = -1
#               CONSTANT NUM_0             = 0
#               CONSTANT NUM_1             = 1
#               CONSTANT NUM_2             = 2
#               CONSTANT NUM_3             = 3
#               CONSTANT NUM_4             = 4
#               CONSTANT TRUE              = 1
#               CONSTANT FALSE             = 0

#               CONSTANT UBN_XREF_LIST_INITIAL = 0  : REM ON = 1, OFF = 0
#               CONSTANT UBN_LIST_LIST_INITIAL = 0  : REM ON = 1, OFF = 0

#               CONSTANT UBN_MEM_PCLEAR        = 1
#               CONSTANT UBN_MEM_FILES_COUNT   = 4
#               CONSTANT UBN_MEM_FILES_SPACE   = 100
#               CONSTANT UBN_MEM_CLEAR         = 8500

#               CONSTANT UBN_MEM_LINE_LABEL_MAX_COUNT                 = 100
#               CONSTANT UBN_MEM_VARIABLE_NAMES_MAX_COUNT             = 150
#               CONSTANT UBN_MEM_KEYWORD_TABLE_MAX_COUNT              = 200
#               CONSTANT UBN_MEM_ILLEGAL_2CH_VARIABLE_TABLE_MAX_COUNT = 10

#               CONSTANT ASC_TAB           = 09  : REM     TAB

#               CONSTANT ASC_BLANK         = 32  : REM ASC(" ")

#               CONSTANT ASC_DOUBLE_QUOTE  = 34  : REM ASC(""")
'               CONSTANT ASC_DOUBLE_QUOTE$ is Defined as a program value, not a constant!
#               CONSTANT ASC_POUND         = 35  : REM ASC("#")
#               CONSTANT ASC_DOLLAR        = 36  : REM ASC("$")
#               CONSTANT ASC_PERCENT       = 37  : REM ASC("%")
#               CONSTANT ASC_AMPERSAND     = 38  : REM ASC("&")
#               CONSTANT ASC_SINGLE_QUOTE  = 39  : REM ASC("'")

#               CONSTANT ASC_PLUS          = 43  : REM ASC("+")
#               CONSTANT ASC_MINUS         = 45  : REM ASC("-")
#               CONSTANT ASC_PERIOD        = 46  : REM ASC(".")

#               CONSTANT ASC_0             = 48 : REM ASC("0")
#               CONSTANT ASC_7             = 55 : REM ASC("7")
#               CONSTANT ASC_8             = 56 : REM ASC("8")
#               CONSTANT ASC_9             = 57 : REM ASC("9")

#               CONSTANT ASC_COLON         = 58  : REM ASC(":")
#               CONSTANT ASC_EQUALS        = 61  : REM ASC("=")
#               CONSTANT ASC_TILDE         = 64  : REM ASC("~")

#               CONSTANT ASC_A_U           = 65  : REM ASC("A")
#               CONSTANT ASC_E_U           = 69  : REM ASC("E")
#               CONSTANT ASC_F_U           = 70  : REM ASC("F")
#               CONSTANT ASC_H_U           = 72  : REM ASC("H")
#               CONSTANT ASC_O_U           = 79  : REM ASC("O")
#               CONSTANT ASC_X_U           = 88  : REM ASC("X")
#               CONSTANT ASC_Z_U           = 90  : REM ASC("Z")

#               CONSTANT ASC_UNDERSCORE    = 95  : REM ASC("_")

#               CONSTANT ASC_a_L           = 97  : REM ASC("a")
#               CONSTANT ASC_e_L           = 101 : REM ASC("e")
#               CONSTANT ASC_f_L           = 102 : REM ASC("f")
#               CONSTANT ASC_h_L           = 104 : REM ASC("h")
#               CONSTANT ASC_o_L           = 111 : REM ASC("o")
#               CONSTANT ASC_x_L           = 120 : REM ASC("x")
#               CONSTANT ASC_z_L           = 122 : REM ASC("z")

#               CONSTANT UBN_XRF_TITLE              = 1
#               CONSTANT UBN_XRF_LINE_LABEL         = 2
#               CONSTANT UBN_XRF_LINE_REFERENCE     = 3
#               CONSTANT UBN_XRF_VARIABLE           = 4
#               CONSTANT UBN_XRF_VARIABLE_REFERENCE = 5
'               CONSTANT UBN_XRF_CONSTANT           = 6
'               CONSTANT UBN_XRF_CONSTANT_REFERENCE = 7
#               CONSTANT UBN_XRF_KEYWORD_REFERENCE  = 8

'               Start of Executation
                GOTO UBN_START

GET_IN_LINE_CHAR IN_LINE_CHAR_COUNTER = IN_LINE_CHAR_COUNTER + NUM_1
                IF  IN_LINE_CHAR_COUNTER > I_LINE_LENGTH GOTO END_IN_LINE

                LAST_CH     = IN_LINE_CH
                IN_LINE_CH$ = MID$(IN_LINE$, IN_LINE_CHAR_COUNTER, NUM_1)
                IN_LINE_CH  = ASC(IN_LINE_CH$)
                IF IN_LINE_CH  >= ASC_BLANK THEN RETURN
                IF IN_LINE_CH   = ASC_TAB GOTO SUBSTUTE_SPACE_FOR_TAB

                PRINT #FILE_L, LINE_NUMBER; " " ; IN_LINE$
                PRINT #FILE_L, LINE_NUMBER; " Control Character "; IN_LINE_CH; " Found in Input Line at "; IN_LINE_CHAR_COUNTER
                RETURN

SUBSTUTE_SPACE_FOR_TAB IN_LINE_CH$ = CHR$(ASC_BLANK)
                IN_LINE_CH  = ASC_BLANK
                RETURN

END_IN_LINE     IN_LINE_CH  = NUM_M1
                IN_LINE_CH$ =  CHR$(ASC_TILDE)
                RETURN

'''
'               On Entry, first character of label or variable is in "IN_LINE_CH$" and "IN_LINE_CH"
'               On Exit, "IN_LINE_CH$" and "IN_LINE_CH" have terminating character (next character not part of VLString).

GET_VLSTRING    VLSTRING$ = IN_LINE_CH$
NEXT_VLSTRING_CH GOSUB GET_IN_LINE_CHAR
                IF IN_LINE_CH  <  NUM_0   THEN RETURN
                IF IN_LINE_CH  >= ASC_A_U AND IN_LINE_CH  <= ASC_Z_U GOTO VLSTRING_ADD_UPPER_ALPHA
                IF IN_LINE_CH  >= ASC_a_L AND IN_LINE_CH  <= ASC_z_L GOTO VLSTRING_ADD_LOWER_ALPHA
                IF IN_LINE_CH  >= ASC_0   AND IN_LINE_CH  <= ASC_9   GOTO VLSTRING_ADD_NUMBER
                IF IN_LINE_CH   = ASC_UNDERSCORE                     GOTO VLSTRING_ADD_SPECIAL
                IF IN_LINE_CH   = ASC_TILDE                          GOTO VLSTRING_ADD_SPECIAL
                IF IN_LINE_CH   = ASC_DOLLAR                         GOTO VLSTRING_ADD_DOLLAR
'               REM Character Found that cannot be in Variable or line Label
                RETURN

VLSTRING_ADD_LOWER_ALPHA IN_LINE_CH   = IN_LINE_CH  - ( ASC_a_L - ASC_A_U )
                IN_LINE_CH$ = CHR$(IN_LINE_CH)
VLSTRING_ADD_UPPER_ALPHA  REM
VLSTRING_ADD_NUMBER       REM
VLSTRING_ADD_SPECIAL      REM
VLSTRING_ADD_DOLLAR       REM
                VLSTRING$ = VLSTRING$ + IN_LINE_CH$
'               If an "ASC_DOLLAR" is found, declare label or variable end found
                IF IN_LINE_CH  =  ASC_DOLLAR THEN LAST_CH = IN_LINE_CH : GOSUB GET_IN_LINE_CHAR : RETURN
                GOTO NEXT_VLSTRING_CH

'''
'               On Entry, "ASC_DOUBLE_QUOTE" is in "IN_LINE_CH$" and "IN_LINE_CH"
'               On Exit, "IN_LINE_CH$" and "IN_LINE_CH" have terminating character or next character.

GET_QSTRING     QSTRING$ = IN_LINE_CH$
                QSTRING_SKIP_VARIABLE = FALSE
MORE_QSTRING    GOSUB GET_IN_LINE_CHAR

                IF IN_LINE_CH <= NUM_0 GOTO BAD_QSTRING
                QSTRING$      =  QSTRING$ + IN_LINE_CH$
                IF IN_LINE_CH =  ASC_BLANK        THEN QSTRING_SKIP_VARIABLE = FALSE
                IF QSTRING_SKIP_VARIABLE = TRUE   GOTO SKIP_VARIABLE
                IF IN_LINE_CH =  ASC_X_U OR IN_LINE_CH  = ASC_x_L GOTO GET_QSTRING_VARIABLE
SKIP_VARIABLE   IF IN_LINE_CH <> ASC_DOUBLE_QUOTE GOTO MORE_QSTRING

                GOSUB GET_IN_LINE_CHAR
                RETURN

GET_QSTRING_VARIABLE GOSUB GET_IN_LINE_CHAR
                IF IN_LINE_CH <= NUM_0                              GOTO BAD_QSTRING
                IF IN_LINE_CH  = ASC_DOUBLE_QUOTE                   GOTO NO_QSVARIABLE
                IF IN_LINE_CH >= ASC_A_U AND IN_LINE_CH  <= ASC_Z_U GOTO GET_QSTRING_VAR
                IF IN_LINE_CH >= ASC_a_L AND IN_LINE_CH  <= ASC_z_L GOTO GET_QSTRING_VAR
                IF IN_LINE_CH  = ASC_UNDERSCORE                     GOTO GET_QSTRING_VAR
                GOTO MORE_QSTRING
NO_QSVARIABLE   QSTRING$   = QSTRING$ + IN_LINE_CH$
                GOSUB GET_IN_LINE_CHAR
                RETURN

GET_QSTRING_VAR QSTRING_CHAR_COUNTER_SAVE = IN_LINE_CHAR_COUNTER
                QSTRING_LAST_CHAR_SAVE$    = IN_LINE_CH$
                GOSUB GET_VLSTRING

                IF LAST_CH  <>  ASC_DOLLAR GOTO NOT_QSTRING_VAR
                FOR  VARIABLE_NAMES_COUNTER = VARIABLE_NAMES_START TO VARIABLE_NAMES_COUNT
                     IF   VLSTRING$ = VARIABLE_NAMES$(VARIABLE_NAMES_COUNTER,VARIABLE_NAMES_NAME) GOTO HAVE_QSTRING_VARIABLE
                NEXT VARIABLE_NAMES_COUNTER

'               Have New Variable

                VARIABLE_NAMES_COUNT = VARIABLE_NAMES_COUNT + NUM_1
                IF  VARIABLE_NAMES_COUNT > VARIABLE_NAMES_MAX_COUNT THEN PRINT #FILE_L, " VARIABLE_NAMES_MAX_COUNT Exceeded" : STOP

                VARIABLE_NAMES$(VARIABLE_NAMES_COUNT,VARIABLE_NAMES_NAME) = VLSTRING$
                VARIABLE_NAMES$(VARIABLE_NAMES_COUNT,VARIABLE_NAMES_2CH)  = "Pending"

                GOSUB GET_NEW_2CH_VARIABLE

                VARIABLE_NAMES$(VARIABLE_NAMES_COUNT,VARIABLE_NAMES_2CH) = NEW_2CH_VARIABLE$ + "$"
                VARIABLE_NAMES_COUNTER = VARIABLE_NAMES_COUNT

HAVE_QSTRING_VARIABLE IF ASC(VARIABLE_NAMES$(VARIABLE_NAMES_COUNTER,VARIABLE_NAMES_2CH)) = ASC_DOUBLE_QUOTE GOTO ADD_QSTRING_CONSTANT

'               Add existing 2ch variable to QUOTE string

                QSTRING$ = QSTRING$ + VARIABLE_NAMES$(VARIABLE_NAMES_COUNTER,VARIABLE_NAMES_2CH)
                GOTO MORE_QSTRING

'               Do Not Include the 'X'
'               Add Constant Without Leading and Trailing Quotes

ADD_QSTRING_CONSTANT QSTRING_LENGTH = LEN(QSTRING$) - NUM_1
                QSTRING$ = LEFT$(QSTRING$,QSTRING_LENGTH)
                QSTRING_CONSTANT_LENGTH = LEN(VARIABLE_NAMES$(VARIABLE_NAMES_COUNTER,VARIABLE_NAMES_2CH)) - NUM_2
                QSTRING$ = QSTRING$ + MID$(VARIABLE_NAMES$(VARIABLE_NAMES_COUNTER,VARIABLE_NAMES_2CH),NUM_2,QSTRING_CONSTANT_LENGTH)
                GOTO MORE_QSTRING

NOT_QSTRING_VAR IN_LINE_CHAR_COUNTER    = QSTRING_CHAR_COUNTER_SAVE
                IN_LINE_CH$               = QSTRING_LAST_CHAR_SAVE$
                QSTRING_SKIP_VARIABLE   = TRUE
                QSTRING$ = QSTRING$ + IN_LINE_CH$
'               PRINT #FILE_L, LINE_NUMBER ; " QSTRING$ = "; QSTRING$; ", IN_LINE_CH = "; IN_LINE_CH
'               PRINT #FILE_L, LINE_NUMBER ; " VLSTRING$ = "; VLSTRING$
                GOTO MORE_QSTRING

                GOSUB GET_IN_LINE_CHAR
                RETURN

BAD_QSTRING     PRINT #FILE_L, LINE_NUMBER ; " ERROR - Missing end of Quoted String "  ; QSTRING$
                ERRORS = ERRORS + NUM_1
                RETURN
GET_NEW_2CH_VARIABLE NEW_2CH_VARIABLE$ = CHR$(HIGH_2CH_VARIABLE) + CHR$(LOW_2CH_VARIABLE)

                LOW_2CH_VARIABLE = LOW_2CH_VARIABLE + NUM_1
                IF  LOW_2CH_VARIABLE <= ASC_Z_U GOTO  CHECK_NEW_2CH_VARIABLE
                LOW_2CH_VARIABLE = ASC_A_U

                HIGH_2CH_VARIABLE = HIGH_2CH_VARIABLE + NUM_1
                IF HIGH_2CH_VARIABLE <= ASC_Z_U GOTO  CHECK_NEW_2CH_VARIABLE
                HIGH_2CH_VARIABLE = ASC_A_U : REM Ignore Possibility of 'ZZ' being exceeded FOR NOW (676 Variables)

CHECK_NEW_2CH_VARIABLE FOR  ILLEGAL_2CH_VARIABLE_TABLE_COUNTER = ILLEGAL_2CH_VARIABLE_TABLE_START TO ILLEGAL_2CH_VARIABLE_TABLE_COUNT
                     IF   NEW_2CH_VARIABLE$ = ILLEGAL_2CH_VARIABLE_TABLE$(ILLEGAL_2CH_VARIABLE_TABLE_COUNTER) GOTO GET_NEW_2CH_VARIABLE
                NEXT ILLEGAL_2CH_VARIABLE_TABLE_COUNTER

                RETURN

'               This is checking if only allowable characters are present
'               It does NOT check for valid number syntax
CHECK_IF_NUMBER IS_NUMBER = FALSE
                NUMBER_LENGTH = LEN(VLSTRING$)
                FOR NUMBER_COUNTER = NUM_1 TO NUMBER_LENGTH

                    NUMBER_CH$  = MID$(VLSTRING$, NUMBER_COUNTER, NUM_1)
                    NUMBER_CH   = ASC(NUMBER_CH$)

                    IF NUMBER_CH  >= ASC_0   AND NUMBER_CH  <= ASC_9    GOTO MORE_NUMBERS
                    IF NUMBER_CH  = ASC_PERIOD OR NUMBER_CH  = ASC_PLUS OR  NUMBER_CH = ASC_MINUS  GOTO MORE_NUMBERS
                    IF NUMBER_CH  = ASC_E_U OR NUMBER_CH  = ASC_e_L     GOTO MORE_NUMBERS

                    RETURN   : REM Not a number

MORE_NUMBERS    NEXT  NUMBER_COUNTER
                IS_NUMBER = TRUE
                RETURN

'               Prepare line number for output, no leading space, No trailing space
PREPARE_LINE_NUMBER LNR_$  = STR$(LINE_NUMBER)
'               IF LEN(LNR_$)  < 2 THEN PRINT #FILE_L, "LINE NUMBER LENGTH LESS THAN 2 >>" ; LEN(LNR_$)
                LN_LENGTH  = LEN(LNR_$) - NUM_1
                LN_$       = MID$(LNR_$, NUM_2, LN_LENGTH)
                RETURN

NEXT_LINE       LINE INPUT #FILE_I, IN_LINE$

                IN_LINE_CHAR_COUNTER = NUM_0
                LAST_CH              = ASC_TILDE
                DEF_CONSTANT         = FALSE
                DATA_LINE            = FALSE
                VLSTRING_COUNT       = NUM_0
'               Let User Know we are still processing
                IF  PASS = NUM_2 THEN PRINT LINE_NUMBER ;
                I_EOF                = EOF(FILE_I)

                IF I_EOF  = NUM_M1 GOTO I_FILE_END
                I_LINE_LENGTH = LEN(IN_LINE$)
                IF  I_LINE_LENGTH = NUM_0 GOTO BLANK_LINE

'''             CHARACTERS IN COLUMN ONE
'               "A-Za-z", "_", "0-9"   =    LINE LABLE
'               "#"                    =    Urbane COMMAND
'               " "                    =    NO LINE LABLE
'               "'"                    =    COMMENT
'               any other character    =    COMMENT

COLUMN_ONE      GOSUB GET_IN_LINE_CHAR
                IF IN_LINE_CH  =  ASC_POUND        GOTO URBANE_COMMAND
                IF IN_LINE_CH  =  ASC_BLANK        GOTO NO_LINE_LABLE
                IF IN_LINE_CH  =  ASC_SINGLE_QUOTE GOTO COMMENT

                IF IN_LINE_CH  >= ASC_A_U AND IN_LINE_CH  <= ASC_Z_U GOTO LINE_LABEL
                IF IN_LINE_CH  >= ASC_a_L AND IN_LINE_CH  <= ASC_z_L GOTO LINE_LABEL
                IF IN_LINE_CH  >= ASC_0   AND IN_LINE_CH  <= ASC_9   GOTO LINE_LABEL
                IF IN_LINE_CH   = ASC_UNDERSCORE                     GOTO LINE_LABEL

COMMENT         ON PASS GOTO OUTPUT_LINE, PASS2_CONTINUE

URBANE_COMMAND  IF INSTR(NUM_2, IN_LINE$, "LIST_ON")  <> NUM_0 THEN OUTPUT_LISTING = TRUE
                IF INSTR(NUM_2, IN_LINE$, "LIST_OFF") <> NUM_0 THEN OUTPUT_LISTING = FALSE

                IF INSTR(NUM_2, IN_LINE$, "XREF_ON")  <> NUM_0 THEN OUTPUT_XREF    = TRUE
                IF INSTR(NUM_2, IN_LINE$, "XREF_OFF") <> NUM_0 THEN OUTPUT_XREF    = FALSE

                IF INSTR(NUM_2, IN_LINE$, "CONSTANT") <> NUM_0 THEN DEF_CONSTANT = TRUE  : GOTO NO_LINE_LABLE

'               ON PASS GOTO OUTPUT_LINE, PASS2_CONTINUE

BLANK_LINE      ON PASS GOTO OUTPUT_LINE, PASS2_CONTINUE

NO_LINE_LABLE   ON PASS GOTO OUTPUT_LINE, PARSE_LINE

LINE_LABEL      GOSUB GET_VLSTRING
                VLSTRING_COUNT = NUM_1

                IF LAST_CH  <>  ASC_DOLLAR GOTO LINE_LABEL_GOOD
                PRINT #FILE_L, "WARNING - '$' SHOULD NOT BE USED IN LABELS "  ; VLSTRING$
                PRINT          "WARNING - '$' SHOULD NOT BE USED IN LABELS "  ; VLSTRING$
                WARNINGS = WARNINGS + NUM_1

LINE_LABEL_GOOD IF PASS = NUM_2 GOTO PARSE_LINE

                FOR  LINE_LABEL_COUNTER = LINE_LABEL_START TO LINE_LABEL_COUNT
                     IF   VLSTRING$ = LINE_LABELS$(LINE_LABEL_COUNTER,LINE_LABELS_NAME) GOTO DUP_LINE_LABEL
                NEXT LINE_LABEL_COUNTER

                 LINE_LABEL_COUNT = LINE_LABEL_COUNT + NUM_1
                IF   LINE_LABEL_COUNT > LINE_LABEL_MAX_COUNT THEN PRINT #FILE_L, " LINE_LABEL_MAX_COUNT Exceeded" : STOP

                LINE_LABELS$(LINE_LABEL_COUNT,LINE_LABELS_NAME) = VLSTRING$
                GOSUB PREPARE_LINE_NUMBER
                LINE_LABELS$(LINE_LABEL_COUNT,LINE_LABELS_NUMBER) = LN_$
                IF OUTPUT_XREF = TRUE THEN PRINT #FILE_X, " "; UBN_XRF_LINE_LABEL; " "; LN_$; " "; VLSTRING$
                GOTO  OUTPUT_LINE

DUP_LINE_LABEL  PRINT #FILE_L, LINE_NUMBER ; " ERROR - DUPLICATE LINE LABEL  = " ; VLSTRING$
                ERRORS = ERRORS + NUM_1
                GOTO OUTPUT_LINE

PARSE_LINE      GOSUB PREPARE_LINE_NUMBER
                OUTPUT_STRING$ = LN_$
                CONSTANT_NAME$ = ""
                CONSTANT_INDEX = NUM_0
                EQUALS_FOUND   = FALSE

PARSE_CONTINUE  IF IN_LINE_CH <  NUM_0                              GOTO OUTPUT_LINE
                IF IN_LINE_CH >= ASC_A_U AND IN_LINE_CH  <= ASC_Z_U GOTO LABEL_OR_VARIABLE
                IF IN_LINE_CH >= ASC_a_L AND IN_LINE_CH  <= ASC_z_L GOTO LABEL_OR_VARIABLE
                IF IN_LINE_CH >= ASC_0   AND IN_LINE_CH  <= ASC_9   GOTO LABEL_OR_VARIABLE
                IF IN_LINE_CH  = ASC_UNDERSCORE                     GOTO LABEL_OR_VARIABLE
                IF IN_LINE_CH  = ASC_DOUBLE_QUOTE                   GOTO HAVE_QUOTED_STRING
                IF IN_LINE_CH  = ASC_AMPERSAND                      GOTO HEX_OR_OCTAL

                IF IN_LINE_CH  = ASC_EQUALS                         THEN EQUALS_FOUND = TRUE

'               Skip blanks
                IF IN_LINE_CH = ASC_BLANK AND LAST_CH = ASC_BLANK GOTO PARSE_GET_NEXT_CH

                OUTPUT_STRING$ = OUTPUT_STRING$ + IN_LINE_CH$

PARSE_GET_NEXT_CH GOSUB GET_IN_LINE_CHAR
                GOTO PARSE_CONTINUE

LABEL_OR_VARIABLE VLSTRING_COUNT = VLSTRING_COUNT + NUM_1
                GOSUB GET_VLSTRING

                GOSUB CHECK_IF_NUMBER
                IF IS_NUMBER = TRUE  GOTO HAVE_NUMBER

                FOR KEYWORD_TABLE_COUNTER = KEYWORD_TABLE_START TO KEYWORD_TABLE_COUNT
                    IF  VLSTRING$ = KEYWORD_TABLE$(KEYWORD_TABLE_COUNTER) GOTO HAVE_KEYWORD
                NEXT KEYWORD_TABLE_COUNTER

                FOR  LINE_LABEL_COUNTER = LINE_LABEL_START TO LINE_LABEL_COUNT
                     IF   VLSTRING$ = LINE_LABELS$(LINE_LABEL_COUNTER,VARIABLE_NAMES_NAME) GOTO HAVE_LINE_LABEL
                NEXT LINE_LABEL_COUNTER

                FOR  VARIABLE_NAMES_COUNTER = VARIABLE_NAMES_START TO VARIABLE_NAMES_COUNT
                     IF   VLSTRING$ = VARIABLE_NAMES$(VARIABLE_NAMES_COUNTER,VARIABLE_NAMES_NAME) GOTO HAVE_VARIABLE
                NEXT VARIABLE_NAMES_COUNTER

'               NEW_VARIABLE FOUND
                VARIABLE_NAMES_COUNT = VARIABLE_NAMES_COUNT + NUM_1
                IF  VARIABLE_NAMES_COUNT > VARIABLE_NAMES_MAX_COUNT THEN PRINT #FILE_L, " VARIABLE_NAMES_MAX_COUNT Exceeded" : STOP

                VARIABLE_NAMES$(VARIABLE_NAMES_COUNT,VARIABLE_NAMES_NAME) = VLSTRING$
                VARIABLE_NAMES$(VARIABLE_NAMES_COUNT,VARIABLE_NAMES_2CH)  = "Pending"
                IF DEF_CONSTANT <> TRUE GOTO GET_NEW_2CH
                CONSTANT_NAME$ = VLSTRING$
                CONSTANT_INDEX = VARIABLE_NAMES_COUNT
                IF OUTPUT_XREF = TRUE THEN PRINT #FILE_X, " "; UBN_XRF_VARIABLE; " "; LN_$; " "; VLSTRING$
                GOTO PARSE_CONTINUE

'               Generate new 2 character variable name and put it into variable name table
GET_NEW_2CH     GOSUB GET_NEW_2CH_VARIABLE

                VARIABLE_NAMES$(VARIABLE_NAMES_COUNT,VARIABLE_NAMES_2CH) = NEW_2CH_VARIABLE$
                VARIABLE_NAMES_COUNTER = VARIABLE_NAMES_COUNT
                IF OUTPUT_XREF = TRUE THEN PRINT #FILE_X, " "; UBN_XRF_VARIABLE; " "; LN_$; " "; VLSTRING$
                IF LAST_CH  <>  ASC_DOLLAR  GOTO HAVE_VARIABLE
                VARIABLE_NAMES$(VARIABLE_NAMES_COUNT,VARIABLE_NAMES_2CH) = NEW_2CH_VARIABLE$ + "$"
                GOTO HAVE_VARIABLE

HAVE_KEYWORD    IF OUTPUT_XREF = TRUE AND DATA_LINE = FALSE THEN PRINT #FILE_X, " "; UBN_XRF_KEYWORD_REFERENCE; " "; LN_$; " "; VLSTRING$
'               Add keyword to output string
                IF  DATA_LINE = TRUE       GOTO HAVE_DATA_LINE
                IF  VLSTRING$ = "REM"      GOTO HAVE_REM
                IF  VLSTRING$ = "LET"      GOTO HAVE_LET
                IF  VLSTRING$ = "DATA"     THEN DATA_LINE = TRUE
                IF  VLSTRING$ = "CONSTANT" GOTO PARSE_CONTINUE
HAVE_DATA_LINE  OUTPUT_STRING$ = OUTPUT_STRING$ + VLSTRING$

                GOTO PARSE_CONTINUE

'               Line with no Line Label and first Keyword "REM" can be removed
'               DECB requires the "REM keyword if there is a label on the line

HAVE_REM        IF VLSTRING_COUNT = NUM_1 GOTO PASS2_CONTINUE
                OUTPUT_STRING$ = OUTPUT_STRING$ + "REM"
                GOTO OUTPUT_LINE

'               Remove unnecessary "LET" and next Blank
HAVE_LET        IF IN_LINE_CH = ASC_BLANK GOTO PARSE_GET_NEXT_CH
                GOTO PARSE_CONTINUE

HAVE_LINE_LABEL IF OUTPUT_XREF = TRUE THEN PRINT #FILE_X, " "; UBN_XRF_LINE_REFERENCE; " "; LN_$; " "; LINE_LABELS$(LINE_LABEL_COUNTER,LINE_LABELS_NUMBER)
'               Add line number to output string
                OUTPUT_STRING$ = OUTPUT_STRING$ + LINE_LABELS$(LINE_LABEL_COUNTER,LINE_LABELS_NUMBER)
                GOTO PARSE_CONTINUE

HAVE_NUMBER     IF   DEF_CONSTANT   <> TRUE  GOTO ADD_NUMBER
                IF   CONSTANT_INDEX  = NUM_0 GOTO ADD_NUMBER
                IF   EQUALS_FOUND   <> TRUE  GOTO ADD_NUMBER

                NUM_PREFIX$ = ""
                IF   LAST_CH = ASC_MINUS THEN NUM_PREFIX$ = "-"
                IF   LAST_CH = ASC_PLUS  THEN NUM_PREFIX$ = "+"

                 VARIABLE_NAMES$(CONSTANT_INDEX,VARIABLE_NAMES_2CH)  = NUM_PREFIX$ + VLSTRING$
                GOTO PARSE_CONTINUE

'               Add number to output string
ADD_NUMBER      OUTPUT_STRING$ = OUTPUT_STRING$ + VLSTRING$
                GOTO PARSE_CONTINUE

HAVE_VARIABLE   IF DEF_CONSTANT = TRUE GOTO PARSE_CONTINUE
                IF OUTPUT_XREF = TRUE THEN PRINT #FILE_X, " "; UBN_XRF_VARIABLE_REFERENCE; " "; LN_$; " "; VLSTRING$
'               Add existing 2ch variable to output string
                OUTPUT_STRING$ = OUTPUT_STRING$ + VARIABLE_NAMES$(VARIABLE_NAMES_COUNTER,VARIABLE_NAMES_2CH)
                GOTO PARSE_CONTINUE

HAVE_QUOTED_STRING GOSUB GET_QSTRING
                IF    DEF_CONSTANT  <> TRUE  GOTO ADD_QUOTED
                IF    CONSTANT_INDEX = NUM_0 GOTO ADD_QUOTED
                IF    EQUALS_FOUND  <> TRUE  GOTO ADD_QUOTED

                VARIABLE_NAMES$(CONSTANT_INDEX,VARIABLE_NAMES_2CH)  = QSTRING$
                GOTO  PARSE_CONTINUE

'               Copy Quoted string to output, with double quotes

ADD_QUOTED      OUTPUT_STRING$ = OUTPUT_STRING$ + QSTRING$
                GOTO PARSE_CONTINUE

'               On Entry, "ASC_AMPERSAND" is in "IN_LINE_CH$" and "IN_LINE_CH"
'               On Exit, "IN_LINE_CH$" and "IN_LINE_CH" have next character.
HEX_OR_OCTAL    HO_STRING$ = IN_LINE_CH$

                GOSUB GET_IN_LINE_CHAR
                HO_STRING$ = HO_STRING$ + IN_LINE_CH$

                HEX   = FALSE
                OCTAL = FALSE
                IF IN_LINE_CH   = ASC_H_U OR  IN_LINE_CH   = ASC_h_L THEN HEX   = TRUE
                IF IN_LINE_CH   = ASC_O_U OR  IN_LINE_CH   = ASC_o_L THEN OCTAL = TRUE
                IF HEX = FALSE AND OCTAL = FALSE GOTO BAD_HEX_OR_OCTAL

MORE_HEX_OR_OCTAL GOSUB GET_IN_LINE_CHAR

                IF IN_LINE_CH  >= ASC_A_U AND IN_LINE_CH  <= ASC_F_U GOTO HOSTRING_ADD_UPPER_HEX
                IF IN_LINE_CH  >= ASC_a_L AND IN_LINE_CH  <= ASC_f_L GOTO HOSTRING_ADD_LOWER_HEX
                IF IN_LINE_CH  >= ASC_0   AND IN_LINE_CH  <= ASC_7   GOTO HOSTRING_ADD_OCTAL
                IF IN_LINE_CH  >= ASC_8   AND IN_LINE_CH  <= ASC_9   GOTO HOSTRING_ADD_UPPER_HEX

'               End of Hex or Octal Number
                OUTPUT_STRING$ = OUTPUT_STRING$ + HO_STRING$
                GOTO PARSE_CONTINUE

HOSTRING_ADD_LOWER_HEX IN_LINE_CH   = IN_LINE_CH  - ( ASC_a_L - ASC_A_U )
                IN_LINE_CH$  = CHR$(IN_LINE_CH)

HOSTRING_ADD_UPPER_HEX HO_STRING$ = HO_STRING$ + IN_LINE_CH$
                IF HEX = TRUE  GOTO MORE_HEX_OR_OCTAL

                PRINT #FILE_L, "WARNING - Invalid Octal Number "  ; HO_STRING$
                PRINT          "WARNING - Invalid Octal Number "  ; HO_STRING$
                WARNINGS = WARNINGS + NUM_1
                GOTO OUTPUT_LINE

HOSTRING_ADD_OCTAL HO_STRING$ = HO_STRING$ + IN_LINE_CH$
                GOTO MORE_HEX_OR_OCTAL

BAD_HEX_OR_OCTAL PRINT #FILE_L, "WARNING - '&' Not followed by 'H' or 'O' "  ; HO_STRING$
                PRINT           "WARNING - '&' Not followed by 'H' or 'O' "  ; HO_STRING$
                WARNINGS = WARNINGS + NUM_1
'               GOTO OUTPUT_LINE

OUTPUT_LINE     IF PASS = NUM_1 AND OUTPUT_LISTING = TRUE THEN PRINT #FILE_L, LINE_NUMBER ; IN_LINE$

                IF DEF_CONSTANT = TRUE GOTO PASS2_CONTINUE

                IF PASS = NUM_2 THEN PRINT #FILE_O, OUTPUT_STRING$

PASS2_CONTINUE  LINE_NUMBER = LINE_NUMBER + NUM_1
                GOTO NEXT_LINE

I_FILE_END      LINE_COUNT = LINE_NUMBER - NUM_1
                PRINT #FILE_L, "Urbane Pass "; PASS; " Done, Lines = "; LINE_COUNT
                PRINT          "Urbane Pass "; PASS; " Done, Lines = "; LINE_COUNT

                IF PASS = NUM_2 GOTO ALL_DONE
'               GOSUB DUMP_LINE_LABELS

                PRINT #FILE_L, " MEM = " ; MEM
                PRINT          " MEM = " ; MEM

LOAD_KEYWORDS   DIM KEYWORD_TABLE$(UBN_MEM_KEYWORD_TABLE_MAX_COUNT)
                KEYWORD_TABLE_MAX_COUNT = UBN_MEM_KEYWORD_TABLE_MAX_COUNT
                KEYWORD_TABLE_START     = NUM_1
                KEYWORD_TABLE_COUNT     = NUM_0

LOOP_KEYWORDS   READ KEYWORD$
                IF   KEYWORD$ = "\" GOTO END_OF_KEYWORDS
                KEYWORD_TABLE_COUNT = KEYWORD_TABLE_COUNT + NUM_1
                KEYWORD_TABLE$(KEYWORD_TABLE_COUNT) = KEYWORD$
                GOTO LOOP_KEYWORDS

END_OF_KEYWORDS DIM ILLEGAL_2CH_VARIABLE_TABLE$(UBN_MEM_ILLEGAL_2CH_VARIABLE_TABLE_MAX_COUNT)
                ILLEGAL_2CH_VARIABLE_TABLE_MAX_COUNT = UBN_MEM_ILLEGAL_2CH_VARIABLE_TABLE_MAX_COUNT
                ILLEGAL_2CH_VARIABLE_TABLE_START     =  NUM_1
                ILLEGAL_2CH_VARIABLE_TABLE_COUNT     =  NUM_0

LOOP_ILLEGAL_2CH_VARIABLES   READ ILLEGAL_2CH_VARIABLE$
                IF ILLEGAL_2CH_VARIABLE$ = "\" GOTO END_OF_ILLEGAL_2CH_VARIABLES
                ILLEGAL_2CH_VARIABLE_TABLE_COUNT = ILLEGAL_2CH_VARIABLE_TABLE_COUNT + NUM_1
                ILLEGAL_2CH_VARIABLE_TABLE$(ILLEGAL_2CH_VARIABLE_TABLE_COUNT) = ILLEGAL_2CH_VARIABLE$
                GOTO LOOP_ILLEGAL_2CH_VARIABLES

END_OF_ILLEGAL_2CH_VARIABLES DIM VARIABLE_NAMES$(UBN_MEM_VARIABLE_NAMES_MAX_COUNT,NUM_2)
                VARIABLE_NAMES_MAX_COUNT       = UBN_MEM_VARIABLE_NAMES_MAX_COUNT
                VARIABLE_NAMES_START           = NUM_1
                VARIABLE_NAMES_COUNT           = NUM_0
                VARIABLE_NAMES_NAME            = NUM_1
                VARIABLE_NAMES_2CH             = NUM_2

                HIGH_2CH_VARIABLE = ASC_A_U
                LOW_2CH_VARIABLE  = ASC_A_U

                PASS        = NUM_2
                LINE_NUMBER = NUM_1
                I_EOF       = NUM_0
                PRINT #FILE_L,  " ---------PASS 2 STARTING------"
                PRINT           " ---------PASS 2 STARTING------"
                CLOSE FILE_I

                OPEN "I", #NUM_1, IN_FILE$

                GOTO NEXT_LINE

'               REM Startup code here so Basic does not have to search it each time it is looking for a line number
UBN_START       FILES  UBN_MEM_FILES_COUNT, UBN_MEM_FILES_SPACE
                PCLEAR UBN_MEM_PCLEAR
                CLEAR  UBN_MEM_CLEAR
                PRINT "Urbane Starting - Urbane XUBN~VERSION$ "
                PRINT " MEM = " ; MEM

                PASS              = NUM_1
                LINE_NUMBER       = NUM_1

                ERRORS            = NUM_0
                WARNINGS          = NUM_0

                ASC_DOUBLE_QUOTE$ = CHR$(34)

                OUTPUT_LISTING    = UBN_LIST_LIST_INITIAL
                OUTPUT_XREF       = UBN_XREF_LIST_INITIAL
                FILE_I = NUM_1
                FILE_O = NUM_2
                FILE_L = NUM_3
                FILE_X = NUM_4

                OPEN "I", #NUM_1, IN_FILE$

                OPEN "O", #NUM_2, OUT_FILE$

                OPEN "O", #NUM_3, LST_FILE$

                OPEN "O", #NUM_4, XRF_FILE$

                DIM  LINE_LABELS$(UBN_MEM_LINE_LABEL_MAX_COUNT,NUM_2)
                LINE_LABEL_MAX_COUNT = UBN_MEM_LINE_LABEL_MAX_COUNT
                LINE_LABEL_START     = NUM_1
                LINE_LABEL_COUNT     = NUM_0
                LINE_LABELS_NAME     = NUM_1
                LINE_LABELS_NUMBER   = NUM_2

                PRINT #FILE_L, " "; UBN_TITLE$
                PRINT #FILE_X, " "; UBN_XRF_TITLE; " "; NUM_0; " "; UBN_TITLE$

                PRINT #FILE_L, " MEM = " ; MEM
                GOTO NEXT_LINE

'               Keyword Table
                DATA REM
                DATA ATTR,AUDIO,BACKUP,CIRCLE,CLEAR,CLOAD,CLOADM,CLOSE,CLS,COLOR,CONSTANT,CONT,COPY,CSAVE
                DATA CSAVEM,DATA,DEF,DEFUSR,DEL,DIM,DIR,DLOAD,DRAW,DRIVE,DSKI$,DSKINI,DSKO$,EDIT
                DATA END,EXEC,FIELD,FILES,FN,FOR,GET,GOSUB
                DATA GOTO,HBUFF,HCIRCLE,HCLS,HCOLOR,HDRAW,HGET,HLINE,HPAINT,HPRINT,HPUT,HRESET
                DATA HSCREEN,HSET,HSTAT,IF,INPUT,KILL,LET,LINE,LIST,LLIST,LOCATE,LPOKE,LOAD,LOADM,LSET,MERGE
                DATA MOTOR,NEW,NEXT,OLD,ON,OPEN,PAINT,PALETTE,PCLEAR,PCLS,PCOPY,PLAY,PMODE,POKE,PRESET,PRINT
                DATA PSET,PUT,READ,RENAME,RENUM,RESET,RSET,RESTORE,RESUME,RETURN,RUN,SAVE,SAVEM,SCREEN
                DATA SET,SKIPF,SOUND,STOP,TO,TROFF,TRON,WIDTH,WRITE,UNLOAD,VERIFY
                DATA MEM,TIMER,AND,NOT,OR,ELSE,STEP,FREE,AS,BRK,ERR,CMP,RGB,USING
                DATA ERROR,FREE,OFF,TAB,USING,THEN,TO,G,BF,B,R,A,"?"
                DATA AS,BF,OR,PI

'               Functions, keywords that require next character to be an open parentheses
                DATA ABS,ASC,ATN,BUTTON,CHR$,COS,CVN,EOF,ERLIN,ERNO,EXP,FIX,HEX$,HPOINT,INKEY$,INSTR,INT
                DATA JOYSTK,LEFT$,LEN,LOC,LOF,LOG,LPEEK,MID$,MKN$,PEEK,POINT,POS,PPOINT,RIGHT$,RND,SGN,SIN
                DATA STRING$,STR$,SQR,TAN,USR,VAL,VARPTR
                DATA "\"

'               Illegal Two Character Variable Table    NOTE: "PI" is a variable that is NOT replaced
                DATA AS,BF,FN,IF,ON,OR,PI,TO,"\"

ALL_DONE        PRINT #FILE_L, " MEM = " ; MEM
                PRINT          " MEM = " ; MEM
'               GOSUB DUMP_VARIABLES
                PRINT          "Urbane Done, Errors = " ; ERRORS ; " Warnings = "; WARNINGS ; " Lines = " ; LINE_COUNT ; "Line Label Count = " ; LINE_LABEL_COUNT ; " Variables Count = " ; VARIABLE_NAMES_COUNT
                PRINT #FILE_L, "Urbane Done, Errors = " ; ERRORS ; " Warnings = "; WARNINGS ; " Lines = " ; LINE_COUNT ; "Line Label Count = " ; LINE_LABEL_COUNT ; " Variables Count = " ; VARIABLE_NAMES_COUNT
                CLOSE FILE_I
                CLOSE FILE_O
                CLOSE FILE_L
                CLOSE FILE_X

                END