home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World 2000 August
/
PCWorld_2000-08_cd.bin
/
Software
/
TemaCD
/
xbasic
/
xbpro.exe
/
xb
/
qbtoxb.x
< prev
next >
Wrap
Text File
|
1999-12-29
|
122KB
|
2,805 lines
'
'
' #################### QuickBasic to XBasic translator
' ##### PROLOG ##### copyright 1999
' #################### Max Reason
'
PROGRAM "qbtoxb"
VERSION "0.0060"
'
IMPORT "xma"
IMPORT "xst"
IMPORT "xgr"
IMPORT "xui"
'
' This software is "open source", subject to the terms and conditions
' of the GPU = "GNU general public license", which is reproduced at
' http://www.opensource.org/licenses/gpl-license.html .
'
' Microsoft distributes a stripped-down QuickBasic product called QBasic,
' but throughout this program, qbasic and QBasic always refer-to QuickBasic.
'
' This program is currently work-in-progress and far from functional.
'
' This following summarizes the flow of this program.
'
' Entry() ' the entry function - start here
' LoadQBasicProgram() ' load QBasic program into qbasic$[]
' QBasicToXBasic() ' translate qbasic$[] source into xbasic$[]
' Initialize() ' initialize everything that needs initializing
' InitializeVariables() ' create and initialize fundamental variables and arrays
' InitializeQBasicTokens() ' defines all QBasic language-defined symbols and tokens
' InitializeXBasicTokens() ' defines all XBasic language-defined symbols and tokens
' InitializeQBasicTokens() ' adds XBasic-equivalent-tokens to QBasic tokens
' InitializeXBasicTokens() ' pass #2 probably not necessary for XBasic
' ParseQBasic() ' parse QBasic source-code into tokens
' CallsManyFunctions ' ParseQBasic() calls many functions
' Translate() ' translate tokens into XBasic source
' TranslateLine() ' translate line of tokens to XBasic
' CallsManyFunctions ' Translate() calls many functions
'
'
' Parsing a QuickBasic program creates an array of token-numbers
' in three-dimensional array #program[function,line,token].
' The lower 24-bits of a token is the token-number, which gives
' access to information about the token at #token[token-number].
' The upper 8-bits of a token contains leading-whitespace info.
' See the TOKEN composite data-type declaration below for details.
'
'
' #######################################
' ##### composite/structure types #####
' #######################################
'
' TOKEN variables hold both QBasic and XBasic tokens.
'
TYPE TOKEN '
XLONG .token ' token number in #token[]
XLONG .string ' string number in #string$[]
XLONG .length ' length of string in characters
XLONG .function ' function number this string is in
XLONG .hashback ' previous token with same hash
XLONG .hashnext ' next token with same hash
XLONG .kindback ' previous token of same kind
XLONG .kindnext ' next token of same kind
XLONG .first ' first executable line in source
XLONG .final ' final executable line in source
XLONG .hash ' hash value of this string
XLONG .kind ' statement, operator, etc.
XLONG .type ' data-type - SBYTE, UBYTE, SSHORT, USHORT, etc.
XLONG .scope ' scope of allocation - AUTO, STATIC, SHARED, EXTERNAL
XLONG .translate ' translate token - in other language
XLONG .address ' address in memory
XLONG .akind[15] ' argument kinds
XLONG .atype[15] ' argument data-types
GIANT .ivalue ' any integer-type value
DOUBLE .fvalue ' floating-point value
XLONG .lineq ' function source line - QB
XLONG .linex ' function source line - XB
XLONG .reserve54 '
XLONG .reserve55 '
XLONG .reserve56 '
XLONG .reserve57 '
XLONG .reserve58 '
XLONG .reserve59 '
XLONG .reserve60 '
XLONG .reserve61 '
XLONG .reserve62 '
XLONG .reserve63 '
END TYPE
'
'
' #######################
' ##### functions #####
' #######################
'
DECLARE FUNCTION Entry ()
DECLARE FUNCTION Initialize ()
DECLARE FUNCTION InitializeVariables ()
DECLARE FUNCTION InitializeQBasicTokens ()
DECLARE FUNCTION InitializeXBasicTokens ()
DECLARE FUNCTION LoadQBasicProgram (@qbasic$[]) ' find and load QBasic program
DECLARE FUNCTION QBasicToXBasic (@qbasic$[], @xbasic$[]) ' translate QBasic to XBasic
DECLARE FUNCTION ParseQBasic () ' parse QBasic program to create tokens
DECLARE FUNCTION Translate () ' translate program tokens to XBasic source
DECLARE FUNCTION TranslateLine (@line[]) ' translate line of tokens to XBasic source
DECLARE FUNCTION TranslateStatement (@line[], @offset) ' translate statement on line to XBasic source
'
DECLARE FUNCTION DeparseTokens (@token[], @line$) ' convert tokens into line of source
DECLARE FUNCTION ParseSourceLine (@line$, @line[]) ' parse source line into tokens
DECLARE FUNCTION ParseWhitespace (@line$, @offset) ' parse whitespace characters
DECLARE FUNCTION ParseCharacter (@line$, @offset) ' parse special character (operators, etc)
DECLARE FUNCTION ParseNumber (@line$, @offset) ' parse numeric string
DECLARE FUNCTION ParseSymbol (@line$, @offset) ' parse symbol
DECLARE FUNCTION GetSymbol (@line$, @offset, @symbol$) ' get symbol
DECLARE FUNCTION OutputToken (@token) ' output token
DECLARE FUNCTION TestForKeyword (@symbol$) ' keyword?
DECLARE FUNCTION MinTypeFromGiant (value$$) ' integer type
DECLARE FUNCTION MinTypeFromDouble (value#) ' float type
'
DECLARE FUNCTION AddKeyword (translate, function, scope, kind, type, atype1, atype2, atype3, @string$)
DECLARE FUNCTION FindToken (@match[], function, scope, kind, type, atype1, atype2, atype3, @string$)
DECLARE FUNCTION AddToken (@token, function, scope, kind, type, atype1, atype2, atype3, @string$)
DECLARE FUNCTION OutputXBasic (@text$[])
DECLARE FUNCTION TokenRestOfLine ()
DECLARE FUNCTION PrintTokens ()
DECLARE FUNCTION PrintHash ()
DECLARE FUNCTION Terminate ()
'
'
'
' ##############################
' ##### shared constants #####
' ##############################
'
$$TYPE_NONE = 0x00000000 ' NONE - type unknown
$$TYPE_VOID = 0x00000001 ' VOID - type prohibited
$$TYPE_SBYTE = 0x00000002 ' SBYTE - 8-bit signed integer
$$TYPE_UBYTE = 0x00000003 ' UBYTE - 8-bit unsigned integer
$$TYPE_SSHORT = 0x00000004 ' SSHORT - 16-bit signed integer
$$TYPE_USHORT = 0x00000005 ' USHORT - 16-bit unsigned integer
$$TYPE_SLONG = 0x00000006 ' SLONG - 32-bit signed integer
$$TYPE_ULONG = 0x00000007 ' ULONG - 32-bit unsigned integer
$$TYPE_XLONG = 0x00000008 ' XLONG - CPU integer
$$TYPE_GOADDR = 0x00000009 ' GOADDR - label address
$$TYPE_SUBADDR = 0x0000000A ' SUBADDR - subroutine address
$$TYPE_FUNCADDR = 0x0000000B ' FUNCADDR - function address
$$TYPE_GIANT = 0x0000000C ' GIANT - 64-bit signed integer
$$TYPE_SINGLE = 0x0000000D ' SINGLE - IEEE 32-bit
$$TYPE_DOUBLE = 0x0000000E ' DOUBLE - IEEE 64-bit
$$TYPE_UNDEFINED = 0x0000000F '
$$TYPE_STRING = 0x00000013 ' STRING - string/array of UBYTEs
$$TYPE_STRING_ASCII = 0x00000013 ' STRING - string/array of UBYTEs
$$TYPE_STRING_UNICODE = 0x00000015 ' UNICODE - string/array of USHORTs
$$TYPE_COMPOSITE_FIRST = 0x00000020 ' first composite type
$$TYPE_COMPOSITE_FINAL = 0x0000FFFF ' final composite type
'
$$FORM_BIT = 0x00010001 ' 0b01001101
$$FORM_OCTAL = 0x00010002 ' 0o01234567
$$FORM_DECIMAL = 0x00010003 ' 1234567890
$$FORM_HEXADECIMAL = 0x00010004 ' 0x0123456789ABCDEF or &H0123456789ABCDEF
'
$$KIND_NONE = 0x00000000 ' kind unknown
$$KIND_STATEMENT = 0x00000001 ' language statement
$$KIND_INTRINSIC = 0x00000002 ' intrinsic function
$$KIND_OPERATOR = 0x00000004 ' OR AND XOR + - * \ / etc.
$$KIND_KEYWORD = 0x00000008 '
$$KIND_LABEL = 0x00000010 ' GOTO label
$$KIND_SUBNAME = 0x00000020 ' GOSUB subname
$$KIND_FUNCTION = 0x00000040 ' function in program
$$KIND_TYPE = 0x00000080 ' data-type
$$KIND_SYMBOL = 0x00000100 ' unknown kind of symbol
$$KIND_LITERAL = 0x00000200 ' number or string
$$KIND_CHARCON = 0x00000400 ' character constant - as in 'a'
$$KIND_CONSTANT = 0x00000800 ' user-defined constant
$$KIND_VARIABLE = 0x00001000 ' simple variable
$$KIND_ARRAY = 0x00002000 ' array variable
$$KIND_COMPOSITE = 0x00004000 ' structure symbol
$$KIND_ELEMENT = 0x00008000 ' structure element
$$KIND_COMMENT = 0x00010000 ' rest of the line
$$KIND_CHARACTER = 0x00020000 ' : ; , ( )
$$KIND_WHITESTRING = 0x00040000 ' string of whitespace
$$KIND_AVAILABLE_19 = 0x00080000 '
$$KIND_AVAILABLE_20 = 0x00100000 '
$$KIND_AVAILABLE_21 = 0x00200000 '
$$KIND_AVAILABLE_22 = 0x00400000 '
$$KIND_AVAILABLE_23 = 0x00800000 '
$$KIND_AVAILABLE_24 = 0x01000000 '
$$KIND_AVAILABLE_25 = 0x02000000 '
$$KIND_AVAILABLE_26 = 0x04000000 '
$$KIND_AVAILABLE_27 = 0x08000000 '
$$KIND_AVAILABLE_28 = 0x10000000 '
$$KIND_AVAILABLE_29 = 0x20000000 '
$$KIND_QBASIC = 0x40000000 ' QBasic language element
$$KIND_XBASIC = 0x80000000 ' XBasic language element
'
$$SCOPE_NONE = 0x00000000 ' scope unknown
$$SCOPE_AUTO = 0x00000001 ' function and temporary
$$SCOPE_AUTOX = 0x00000002 ' function and temporary
$$SCOPE_STATIC = 0x00000003 ' function and permanent
$$SCOPE_SHARED = 0x00000004 ' program and permanent
$$SCOPE_SHARED_NAME = 0x00000005 ' program and permanent - sharename
$$SCOPE_EXTERNAL = 0x00000006 ' modules and permanent - static linked modules
$$SCOPE_EXTERNAL_NAME = 0x00000007 ' modules and permanent - static linked modules - sharename
'
$$MIN_SBYTE = -128
$$MAX_SBYTE = 127
$$MIN_UBYTE = 0
$$MAX_UBYTE = 255
$$MIN_SSHORT = -32768
$$MAX_SSHORT = 32767
$$MIN_USHORT = 0
$$MAX_USHORT = 65535
$$MIN_SLONG = -2147483648
$$MAX_SLONG = 2147483647
$$MIN_ULONG = 0
$$MAX_ULONG = 4294967395$$
$$MIN_XLONG = $$MIN_SLONG
$$MAX_XLONG = $$MAX_ULONG
$$MIN_GOADDR = $$MIN_XLONG
$$MAX_GOADDR = $$MAX_XLONG
$$MIN_SUBADDR = $$MIN_XLONG
$$MAX_SUBADDR = $$MAX_XLONG
$$MIN_FUNCADDR = $$MIN_XLONG
$$MAX_FUNCADDR = $$MAX_XLONG
$$MIN_SINGLE = 0sFF7FFFFF
$$MAX_SINGLE = 0s7F7FFFFF
$$MIN_DOUBLE = 0dFFEFFFFFFFFFFFFF
$$MAX_DOUBLE = 0d7FEFFFFFFFFFFFFF
$$MIN_GIANT = 0x8000000000000000
$$MAX_GIANT = 0x7FFFFFFFFFFFFFFF
'
'
' ##############################
' ##### shared variables #####
' ##############################
'
TOKEN #toktemp ' temporary - for compiler tests
XLONG #print ' temporary - for debugging
'
XLONG #pass ' pass # for parse or compile
XLONG #line ' current line in function
XLONG #token ' current token on line
XLONG #function ' function being parsed or translated
XLONG #whitebyte ' whitestring # = entry in #whitestring$[]
'
XLONG #ustring ' upper-bound of #string$[]
XLONG #nstring ' next slot in #string$[]
XLONG #utoken ' upper-bound of #token[]
XLONG #ntoken ' next slot in #token[]
'
XLONG #quline ' upper QBasic source-code line
XLONG #qnline ' next QBasic source-code line
XLONG #xuline ' upper XBasic source-code line
XLONG #xnline ' next XBasic source-code line
'
XLONG #qatoken ' first QBasic keyword token-number
XLONG #qztoken ' final QBasic keyword token-number
XLONG #xatoken ' first XBasic keyword token-number
XLONG #xztoken ' final XBasic keyword token-number
'
USHORT #hx[] ' hash mixer
XLONG #hash[] ' hash table
XLONG #kind[] ' first token of each kind
TOKEN #token[] ' holds all symbol-table tokens
STRING #string$[] ' holds all symbol-table strings
XLONG #program[] ' holds token-numbers for entire program : #program[function,line,token]
XLONG #functoken[] ' holds token-number of every function in the program
XLONG #whitetoken[] ' token-numbers of 256 leading-whitespace strings representable in upper-byte of tokens
'
STRING #qbasic$[] ' holds entire QBasic source program
STRING #xbasic$[] ' holds entire XBasic source program
'
' the following arrays test and/or convert characters in a single array access
'
UBYTE #charsetSymbolFirst[]
UBYTE #charsetSymbolInner[]
UBYTE #charsetSymbolFinal[]
UBYTE #charsetSymbol[]
UBYTE #charsetUpper[]
UBYTE #charsetLower[]
UBYTE #charsetNumeric[]
UBYTE #charsetUpperLower[]
UBYTE #charsetUpperNumeric[]
UBYTE #charsetLowerNumeric[]
UBYTE #charsetUpperLowerNumeric[]
UBYTE #charsetUpperToLower[]
UBYTE #charsetLowerToUpper[]
UBYTE #charsetVex[]
UBYTE #charsetHexUpper[]
UBYTE #charsetHexLower[]
UBYTE #charsetHexUpperLower[]
UBYTE #charsetHexUpperToLower[]
UBYTE #charsetHexLowerToUpper[]
UBYTE #charsetBackslash[]
UBYTE #charsetBackslashByte[]
UBYTE #charsetBackslashChar[]
UBYTE #charsetNormalChar[]
UBYTE #charsetOctal[]
UBYTE #charsetPrintChar[]
UBYTE #charsetSuffix[]
UBYTE #charsetSpaceTab[]
UBYTE #charsetWhitespace[]
'
'
' ######################
' ##### Entry () #####
' ######################
'
FUNCTION Entry ()
'
XstGetConsoleGrid (@console)
XgrGetDisplaySize ("", @#displayWidth, @#displayHeight, @#windowBorderWidth, @#windowTitleHeight)
maxwidth = #displayWidth - #windowBorderWidth - #windowBorderWidth
XuiSendStringMessage (console, @"GetSize", @x, @y, @w, @h, 0, 0)
width = MIN (maxwidth, 1016)
height = h
'
' set console width for printing speed efficiency and smoothness
'
XuiSendStringMessage (console, @"Resize", 0, 0, width, height, 0, 0)
'
LoadQBasicProgram (@qbasic$[]) ' load QBasic program into qbasic$[]
QBasicToXBasic (@qbasic$[], @xbasic$[]) ' translate qbasic$[] into xbasic$[]
END FUNCTION
'
'
' ###########################
' ##### Initialize () #####
' ###########################
'
FUNCTION Initialize ()
'
#print = 1
'
#pass = 0 '
InitializeVariables () ' create arrays for tokens, symbols, etc.
'
#pass = 1
#ntoken = 0 ' zero token number
#nstring = 0 ' zero string number
InitializeXBasicTokens () ' pass 1 cannot fill-in equivalent QBasic tokens
InitializeQBasicTokens () ' pass 1 cannot fill-in equivalent XBasic tokens
'
#pass = 2
#ntoken = 0 ' zero token number
#nstring = 0 ' zero string number
InitializeXBasicTokens () ' pass 2 can fill-in equivalent QBasic tokens
InitializeQBasicTokens () ' pass 2 can fill-in equivalent XBasic tokens
'
#pass = 0 '
IF #print THEN PrintTokens () ' look at the tokens
'
IF #print THEN
PRINT " "; HEX$(#xatoken,4);; HEX$(#xztoken,4);; HEX$(#qatoken,4);; HEX$(#qztoken,4)
PRINT
PrintHash () ' look at hash table
END IF
END FUNCTION
'
'
' ####################################
' ##### InitializeVariables () #####
' ####################################
'
FUNCTION InitializeVariables ()
'
#nwhite = 0 ' start at white 0
#ntoken = 0 ' start at token 0
#nstring = 0 ' start at string 0
#function = 0 ' start with PROLOG
'
#uhash = 255 ' 8-bit hash size for now
#uwhite = 255 ' maximum of 255 whitestrings
#utoken = 4095 ' start with room for 4096 tokens
#ustring = 4095 ' start with room for 4096 strings
#ufunction = 1023 ' start with room for 1024 functions
#uwhitestring = 255 ' never more than 255 leading-whitestring tokens
'
DIM #hx[255] ' dimension hash mix
DIM #hash[#uhash] ' dimension hash array
DIM #token[#utoken] ' dimension token array
DIM #string$[#ustring] ' dimension string array
DIM #program[#ufunction,] ' dimension program array
DIM #functoken[#ufunction] ' dimension function array
DIM #whitetoken[#uwhitestring] ' dimension whitetoken array
DIM #whitestring$[#uwhitestring] ' dimension whitestring array
'
#hx[ 0] = 0xF3C9 : #hx[ 64] = 0x811D : #hx[128] = 0x199C : #hx[192] = 0xD0C8
#hx[ 1] = 0xE034 : #hx[ 65] = 0xC6E3 : #hx[129] = 0x1299 : #hx[193] = 0x3C07
#hx[ 2] = 0xB37C : #hx[ 66] = 0xCA5D : #hx[130] = 0xA314 : #hx[194] = 0xDDCA
#hx[ 3] = 0x4E31 : #hx[ 67] = 0x5AF2 : #hx[131] = 0xEF45 : #hx[195] = 0xB2C1
#hx[ 4] = 0xC0DE : #hx[ 68] = 0xB2F3 : #hx[132] = 0xEFC3 : #hx[196] = 0x6A7C
#hx[ 5] = 0x2487 : #hx[ 69] = 0xCF28 : #hx[133] = 0x8A2D : #hx[197] = 0x5E02
#hx[ 6] = 0x98E2 : #hx[ 70] = 0x4714 : #hx[134] = 0x2553 : #hx[198] = 0x4C8B
#hx[ 7] = 0x557C : #hx[ 71] = 0x32B0 : #hx[135] = 0x8CA6 : #hx[199] = 0x6652
#hx[ 8] = 0xA6CB : #hx[ 72] = 0x9A76 : #hx[136] = 0x60B8 : #hx[200] = 0x3C50
#hx[ 9] = 0x410D : #hx[ 73] = 0xB2A4 : #hx[137] = 0x2192 : #hx[201] = 0x02B8
#hx[ 10] = 0x7767 : #hx[ 74] = 0xDE9B : #hx[138] = 0xA15C : #hx[202] = 0x7B70
#hx[ 11] = 0x3861 : #hx[ 75] = 0xE0E1 : #hx[139] = 0xA527 : #hx[203] = 0x118F
#hx[ 12] = 0x5517 : #hx[ 76] = 0xA7C3 : #hx[140] = 0x1FAC : #hx[204] = 0xEF65
#hx[ 13] = 0x0918 : #hx[ 77] = 0x0E48 : #hx[141] = 0xC554 : #hx[205] = 0x3D6E
#hx[ 14] = 0xF3AF : #hx[ 78] = 0xFABE : #hx[142] = 0x5ECB : #hx[206] = 0xCAB2
#hx[ 15] = 0x2EAB : #hx[ 79] = 0xE351 : #hx[143] = 0x7941 : #hx[207] = 0x23F0
#hx[ 16] = 0x210D : #hx[ 80] = 0x4419 : #hx[144] = 0x3EA2 : #hx[208] = 0x927F
#hx[ 17] = 0xDF19 : #hx[ 81] = 0x5AB4 : #hx[145] = 0xE73D : #hx[209] = 0x1F12
#hx[ 18] = 0x2F0B : #hx[ 82] = 0xDDF9 : #hx[146] = 0xDE62 : #hx[210] = 0xEDCE
#hx[ 19] = 0x269A : #hx[ 83] = 0x513E : #hx[147] = 0x9FFA : #hx[211] = 0x0D52
#hx[ 20] = 0xE171 : #hx[ 84] = 0x1BDF : #hx[148] = 0x0CE8 : #hx[212] = 0x69B5
#hx[ 21] = 0x8D07 : #hx[ 85] = 0xA0BC : #hx[149] = 0x8683 : #hx[213] = 0x9DC4
#hx[ 22] = 0x0AF1 : #hx[ 86] = 0xC2E5 : #hx[150] = 0x481C : #hx[214] = 0x910F
#hx[ 23] = 0x4627 : #hx[ 87] = 0x5917 : #hx[151] = 0x80E4 : #hx[215] = 0xEE6D
#hx[ 24] = 0x7C4B : #hx[ 88] = 0x0448 : #hx[152] = 0xC43E : #hx[216] = 0xA0E7
#hx[ 25] = 0xA59A : #hx[ 89] = 0xE110 : #hx[153] = 0x7830 : #hx[217] = 0xF2ED
#hx[ 26] = 0x561F : #hx[ 90] = 0xA4C8 : #hx[154] = 0x3952 : #hx[218] = 0x6EA2
#hx[ 27] = 0x1F90 : #hx[ 91] = 0x5BC6 : #hx[155] = 0x2BBA : #hx[219] = 0xFEFC
#hx[ 28] = 0x9407 : #hx[ 92] = 0x1250 : #hx[156] = 0x476D : #hx[220] = 0x0A20
#hx[ 29] = 0xAAAA : #hx[ 93] = 0x3D09 : #hx[157] = 0xF307 : #hx[221] = 0xA568
#hx[ 30] = 0x404B : #hx[ 94] = 0xD230 : #hx[158] = 0x5A6A : #hx[222] = 0xB90E
#hx[ 31] = 0xCCB2 : #hx[ 95] = 0x19F1 : #hx[159] = 0x232A : #hx[223] = 0xFA26
#hx[ 32] = 0xB6B8 : #hx[ 96] = 0x28D0 : #hx[160] = 0x36DA : #hx[224] = 0xFB8E
#hx[ 33] = 0x93E5 : #hx[ 97] = 0x0FD7 : #hx[161] = 0x1448 : #hx[225] = 0x3091
#hx[ 34] = 0xCD83 : #hx[ 98] = 0x79BD : #hx[162] = 0x016A : #hx[226] = 0x56A1
#hx[ 35] = 0x8392 : #hx[ 99] = 0xE856 : #hx[163] = 0xF0CC : #hx[227] = 0x184A
#hx[ 36] = 0x951B : #hx[100] = 0xDDDE : #hx[164] = 0x5328 : #hx[228] = 0xDEC0
#hx[ 37] = 0x983F : #hx[101] = 0xBD28 : #hx[165] = 0x8B83 : #hx[229] = 0xC39F
#hx[ 38] = 0x1BB3 : #hx[102] = 0xD9F7 : #hx[166] = 0x1566 : #hx[230] = 0xBED3
#hx[ 39] = 0x40A7 : #hx[103] = 0xCBB9 : #hx[167] = 0xB0D3 : #hx[231] = 0x51F5
#hx[ 40] = 0x5D7E : #hx[104] = 0x9B85 : #hx[168] = 0xCE2F : #hx[232] = 0xC0E9
#hx[ 41] = 0x65A1 : #hx[105] = 0x82DC : #hx[169] = 0x30FA : #hx[233] = 0x617B
#hx[ 42] = 0x8576 : #hx[106] = 0x67B0 : #hx[170] = 0x49C6 : #hx[234] = 0xF6E9
#hx[ 43] = 0xAC39 : #hx[107] = 0x8720 : #hx[171] = 0x94D9 : #hx[235] = 0x9775
#hx[ 44] = 0xFE04 : #hx[108] = 0x0CDF : #hx[172] = 0xE69B : #hx[236] = 0xD5A5
#hx[ 45] = 0x6C6F : #hx[109] = 0xA884 : #hx[173] = 0x7B2C : #hx[237] = 0xF7D3
#hx[ 46] = 0x838F : #hx[110] = 0x238D : #hx[174] = 0x340B : #hx[238] = 0x2BD5
#hx[ 47] = 0xDA44 : #hx[111] = 0xACED : #hx[175] = 0x2E46 : #hx[239] = 0xBB3D
#hx[ 48] = 0x7B93 : #hx[112] = 0x773B : #hx[176] = 0xFD83 : #hx[240] = 0x1483
#hx[ 49] = 0x851E : #hx[113] = 0x84F1 : #hx[177] = 0xB1A9 : #hx[241] = 0x5906
#hx[ 50] = 0xD23F : #hx[114] = 0xB1A6 : #hx[178] = 0x6F78 : #hx[242] = 0x6D25
#hx[ 51] = 0x1F47 : #hx[115] = 0x049F : #hx[179] = 0xF3FE : #hx[243] = 0x0BEE
#hx[ 52] = 0x7C74 : #hx[116] = 0x8B30 : #hx[180] = 0x387B : #hx[244] = 0xE76B
#hx[ 53] = 0xBF9D : #hx[117] = 0xB545 : #hx[181] = 0xCCC2 : #hx[245] = 0x6751
#hx[ 54] = 0x7646 : #hx[118] = 0x48EC : #hx[182] = 0x762C : #hx[246] = 0x2A06
#hx[ 55] = 0xC9FF : #hx[119] = 0xF885 : #hx[183] = 0x603E : #hx[247] = 0x49E3
#hx[ 56] = 0x7944 : #hx[120] = 0x3985 : #hx[184] = 0x02F9 : #hx[248] = 0x9854
#hx[ 57] = 0x953D : #hx[121] = 0x3D6A : #hx[185] = 0x3F51 : #hx[249] = 0x11F4
#hx[ 58] = 0xE666 : #hx[122] = 0x6871 : #hx[186] = 0x6C2E : #hx[250] = 0xA655
#hx[ 59] = 0xB2DA : #hx[123] = 0x2F08 : #hx[187] = 0x0777 : #hx[251] = 0x742F
#hx[ 60] = 0x743C : #hx[124] = 0x94DE : #hx[188] = 0xE456 : #hx[252] = 0x8C19
#hx[ 61] = 0xDB99 : #hx[125] = 0x4CA5 : #hx[189] = 0x7AA0 : #hx[253] = 0xB74A
#hx[ 62] = 0x48BB : #hx[126] = 0xD5EA : #hx[190] = 0x0766 : #hx[254] = 0xD219
#hx[ 63] = 0xF794 : #hx[127] = 0xAD4C : #hx[191] = 0x4882 : #hx[255] = 0x63DD
'
'
' dimension charset arrays - all have 256 entries, one for each byte/character value
'
DIM #charsetSymbolFirst[255]
DIM #charsetSymbolInner[255]
DIM #charsetSymbolFinal[255]
DIM #charsetSymbol[255]
DIM #charsetUpper[255]
DIM #charsetLower[255]
DIM #charsetNumeric[255]
DIM #charsetUpperLower[255]
DIM #charsetUpperNumeric[255]
DIM #charsetLowerNumeric[255]
DIM #charsetUpperLowerNumeric[255]
DIM #charsetUpperToLower[255]
DIM #charsetLowerToUpper[255]
DIM #charsetVex[255]
DIM #charsetHexUpper[255]
DIM #charsetHexLower[255]
DIM #charsetHexUpperLower[255]
DIM #charsetHexUpperToLower[255]
DIM #charsetHexLowerToUpper[255]
DIM #charsetBackslash[255]
DIM #charsetBackslashByte[255]
DIM #charsetBackslashChar[255]
DIM #charsetNormalChar[255]
DIM #charsetOctal[255]
DIM #charsetPrintChar[255]
DIM #charsetSuffix[255]
DIM #charsetSpaceTab[255]
DIM #charsetWhitespace[255]
'
'
' ***********************************
' ***** #charsetSymbolFirst[] ***** A-Z a-z (others 0)
' ***********************************
'
FOR i = 0 TO 255
SELECT CASE TRUE
CASE ((i >= 'A') AND (i <= 'Z')) : #charsetSymbolFirst[i] = i
CASE ((i >= 'a') AND (i <= 'z')) : #charsetSymbolFirst[i] = i
CASE (i = '_') : #charsetSymbolFirst[i] = i
CASE ELSE : #charsetSymbolFirst[i] = 0
END SELECT
NEXT i
'
'
' ***********************************
' ***** #charsetSymbolInner[] ***** A-Z a-z 0-9 "_" (others 0)
' ***********************************
'
FOR i = 0 TO 255
SELECT CASE TRUE
CASE ((i >= '0') AND (i <= '9')) : #charsetSymbolInner[i] = i
CASE ((i >= 'A') AND (i <= 'Z')) : #charsetSymbolInner[i] = i
CASE ((i >= 'a') AND (i <= 'z')) : #charsetSymbolInner[i] = i
CASE (i = '_') : #charsetSymbolInner[i] = i
CASE ELSE : #charsetSymbolInner[i] = 0
END SELECT
NEXT i
'
'
' ***********************************
' ***** #charsetSymbolFinal[] ***** A-Z a-z 0-9 "_" (others 0)
' ***********************************
'
FOR i = 0 TO 255
SELECT CASE TRUE
CASE ((i >= '0') AND (i <= '9')) : #charsetSymbolFinal[i] = i
CASE ((i >= 'A') AND (i <= 'Z')) : #charsetSymbolFinal[i] = i
CASE ((i >= 'a') AND (i <= 'z')) : #charsetSymbolFinal[i] = i
CASE (i = '_') : #charsetSymbolFinal[i] = i
CASE ELSE : #charsetSymbolFinal[i] = 0
END SELECT
NEXT i
'
'
' ******************************
' ***** #charsetSymbol[] ***** A-Z a-z 0-9 "_" (others 0)
' ******************************
'
FOR i = 0 TO 255
SELECT CASE TRUE
CASE ((i >= '0') AND (i <= '9')) : #charsetSymbol[i] = i
CASE ((i >= 'A') AND (i <= 'Z')) : #charsetSymbol[i] = i
CASE ((i >= 'a') AND (i <= 'z')) : #charsetSymbol[i] = i
CASE (i = '_') : #charsetSymbol[i] = i
CASE ELSE : #charsetSymbol[i] = 0
END SELECT
NEXT i
'
'
' *****************************
' ***** #charsetUpper[] ***** A-Z (others 0)
' *****************************
'
FOR i = 0 TO 255
SELECT CASE TRUE
CASE ((i >= 'A') AND (i <= 'Z')) : #charsetUpper[i] = i
CASE ELSE : #charsetUpper[i] = 0
END SELECT
NEXT i
'
'
' *****************************
' ***** #charsetLower[] ***** a-z (others 0)
' *****************************
'
FOR i = 0 TO 255
SELECT CASE TRUE
CASE ((i >= 'a') AND (i <= 'z')) : #charsetLower[i] = i
CASE ELSE : #charsetLower[i] = 0
END SELECT
NEXT i
'
'
' *******************************
' ***** #charsetNumeric[] ***** 0-9 (others 0)
' *******************************
'
FOR i = 0 TO 255
SELECT CASE TRUE
CASE ((i >= '0') AND (i <= '9')) : #charsetNumeric[i] = i
CASE ELSE : #charsetNumeric[i] = 0
END SELECT
NEXT i
'
'
' **********************************
' ***** #charsetUpperLower[] ***** A-Z a-z (others 0)
' **********************************
'
FOR i = 0 TO 255
SELECT CASE TRUE
CASE ((i >= 'A') AND (i <= 'Z')) : #charsetUpperLower[i] = i
CASE ((i >= 'a') AND (i <= 'z')) : #charsetUpperLower[i] = i
CASE ELSE : #charsetUpperLower[i] = 0
END SELECT
NEXT i
'
'
' ************************************
' ***** #charsetUpperNumeric[] ***** A-Z 0-9 (others 0)
' ************************************
'
FOR i = 0 TO 255
SELECT CASE TRUE
CASE ((i >= '0') AND (i <= '9')) : #charsetUpperNumeric[i] = i
CASE ((i >= 'A') AND (i <= 'Z')) : #charsetUpperNumeric[i] = i
CASE ELSE : #charsetUpperNumeric[i] = 0
END SELECT
NEXT i
'
'
' ************************************
' ***** #charsetLowerNumeric[] ***** a-z 0-9 (others 0)
' ************************************
'
FOR i = 0 TO 255
SELECT CASE TRUE
CASE ((i >= '0') AND (i <= '9')) : #charsetLowerNumeric[i] = i
CASE ((i >= 'a') AND (i <= 'z')) : #charsetLowerNumeric[i] = i
CASE ELSE : #charsetLowerNumeric[i] = 0
END SELECT
NEXT i
'
'
' *****************************************
' ***** #charsetUpperLowerNumeric[] ***** A-Z a-z 0-9 (others 0)
' *****************************************
'
FOR i = 0 TO 255
SELECT CASE TRUE
CASE ((i >= '0') AND (i <= '9')) : #charsetUpperLowerNumeric[i] = i
CASE ((i >= 'A') AND (i <= 'Z')) : #charsetUpperLowerNumeric[i] = i
CASE ((i >= 'a') AND (i <= 'z')) : #charsetUpperLowerNumeric[i] = i
CASE ELSE : #charsetUpperLowerNumeric[i] = 0
END SELECT
NEXT i
'
'
' ************************************
' ***** #charsetUpperToLower[] ***** A-Z ==>> a-z (others unchanged)
' ************************************
'
FOR i = 0 TO 255
SELECT CASE TRUE
CASE ((i >= 'A') AND (i <= 'Z')) : #charsetUpperToLower[i] = i + 32
CASE ELSE : #charsetUpperToLower[i] = i
END SELECT
NEXT i
'
'
' ************************************
' ***** #charsetLowerToUpper[] ***** a-z ==>> A-Z (others unchanged)
' ************************************
'
FOR i = 0 TO 255
SELECT CASE TRUE
CASE ((i >= 'a') AND (i <= 'z')) : #charsetLowerToUpper[i] = i - 32
CASE ELSE : #charsetLowerToUpper[i] = i
END SELECT
NEXT i
'
'
' ***************************
' ***** #charsetVex[] ***** 0-9 A-V (others 0)
' ***************************
'
FOR i = 0 TO 255
SELECT CASE TRUE
CASE ((i >= '0') AND (i <= '9')) : #charsetVex[i] = i
CASE ((i >= 'A') AND (i <= 'V')) : #charsetVex[i] = i
CASE ELSE : #charsetVex[i] = 0
END SELECT
NEXT i
'
'
' *****************************
' ***** #charsetOctal[] ***** 0-7
' *****************************
'
FOR i = 0 TO 255
SELECT CASE TRUE
CASE ((i >= '0') AND (i <= '7')) : #charsetHexUpper[i] = i
CASE ELSE : #charsetHexUpper[i] = 0
END SELECT
NEXT i
'
'
' ********************************
' ***** #charsetHexUpper[] ***** 0-9 A-F (others 0)
' ********************************
'
FOR i = 0 TO 255
SELECT CASE TRUE
CASE ((i >= '0') AND (i <= '9')) : #charsetHexUpper[i] = i
CASE ((i >= 'A') AND (i <= 'F')) : #charsetHexUpper[i] = i
CASE ELSE : #charsetHexUpper[i] = 0
END SELECT
NEXT i
'
'
' ********************************
' ***** #charsetHexLower[] ***** 0-9 a-f (others 0)
' ********************************
'
FOR i = 0 TO 255
SELECT CASE TRUE
CASE ((i >= '0') AND (i <= '9')) : #charsetHexLower[i] = i
CASE ((i >= 'a') AND (i <= 'f')) : #charsetHexLower[i] = i
CASE ELSE : #charsetHexLower[i] = 0
END SELECT
NEXT i
'
'
' *************************************
' ***** #charsetHexUpperLower[] ***** 0-9 A-F a-f (others 0)
' *************************************
'
FOR i = 0 TO 255
SELECT CASE TRUE
CASE ((i >= '0') AND (i <= '9')) : #charsetHexUpperLower[i] = i
CASE ((i >= 'A') AND (i <= 'F')) : #charsetHexUpperLower[i] = i
CASE ((i >= 'a') AND (i <= 'f')) : #charsetHexUpperLower[i] = i
CASE ELSE : #charsetHexUpperLower[i] = 0
END SELECT
NEXT i
'
'
' *************************************** 0-9
' ***** #charsetHexUpperToLower[] ***** A-F ==>> a-f (others 0)
' *************************************** a-f
'
FOR i = 0 TO 255
SELECT CASE TRUE
CASE ((i >= '0') AND (i <= '9')) : #charsetHexUpperToLower[i] = i
CASE ((i >= 'A') AND (i <= 'F')) : #charsetHexUpperToLower[i] = i + 32
CASE ((i >= 'a') AND (i <= 'f')) : #charsetHexUpperToLower[i] = i
CASE ELSE : #charsetHexUpperToLower[i] = 0
END SELECT
NEXT i
'
'
' *************************************** 0-9
' ***** #charsetHexLowerToUpper[] ***** a-f ==>> A-F (others 0)
' *************************************** A-F
'
FOR i = 0 TO 255
SELECT CASE TRUE
CASE ((i >= '0') AND (i <= '9')) : #charsetHexLowerToUpper[i] = i
CASE ((i >= 'A') AND (i <= 'F')) : #charsetHexLowerToUpper[i] = i
CASE ((i >= 'a') AND (i <= 'f')) : #charsetHexLowerToUpper[i] = i - 32
CASE ELSE : #charsetHexLowerToUpper[i] = 0
END SELECT
NEXT i
'
'
' ********************************* \a \b \d \f \n \r \v \\ \" \z
' ***** #charsetBackslash[] ***** \0 - \V
' ********************************* (others unchanged)
'
' Convert character following a \ into the proper binary value
' For all characters without special binary values, return the character
'
offset = 10 - 'A'
FOR i = 0 TO 255
SELECT CASE TRUE
CASE ((i >= '0') AND (i <= '9')) : #charsetBackslash[i] = i - '0'
CASE ((i >= 'A') AND (i <= 'V')) : #charsetBackslash[i] = i + offset
CASE ELSE : #charsetBackslash[i] = i
END SELECT
NEXT i
'
FOR i = 0 TO 255
SELECT CASE i
CASE '\\' : #charsetBackslash[i] = 0x5C ' backslash
CASE '"' : #charsetBackslash[i] = 0x22 ' double-quote
CASE 'a' : #charsetBackslash[i] = 0x07 ' alarm (bell)
CASE 'b' : #charsetBackslash[i] = 0x08 ' backspace
CASE 'd' : #charsetBackslash[i] = 0x7F ' delete
CASE 'e' : #charsetBackslash[i] = 0x1B ' escape
CASE 'f' : #charsetBackslash[i] = 0x0C ' form-feed
CASE 'n' : #charsetBackslash[i] = 0x0A ' newline
CASE 'r' : #charsetBackslash[i] = 0x0D ' return
CASE 't' : #charsetBackslash[i] = 0x09 ' tab
CASE 'v' : #charsetBackslash[i] = 0x0B ' vertical-tab
CASE 'z' : #charsetBackslash[i] = 0xFF ' finale (highest UBYTE)
END SELECT
NEXT i
'
'
' ************************************* \a \b \d \e \f \n \r \t \v
' ***** #charsetBackslashByte[] ***** \\ \"
' *************************************
'
' Return printable character intended to follow \ backslash character for
' SIMPLE (only simple) 1 character backslash codes, as understood by dumb
' assemblers, for example. Otherwise, return zero.
'
FOR i = 0 TO 255
SELECT CASE i
CASE 0x5C : #charsetBackslashByte[i] = '\\' ' backslash
CASE 0x22 : #charsetBackslashByte[i] = '"' ' double-quote
CASE 0x07 : #charsetBackslashByte[i] = 'a' ' alarm (bell)
CASE 0x08 : #charsetBackslashByte[i] = 'b' ' backspace
CASE 0x7F : #charsetBackslashByte[i] = 'd' ' delete
CASE 0x1B : #charsetBackslashByte[i] = 'e' ' escape
CASE 0x0C : #charsetBackslashByte[i] = 'f' ' form-feed
CASE 0x0A : #charsetBackslashByte[i] = 'n' ' newline
CASE 0x0D : #charsetBackslashByte[i] = 'r' ' return
CASE 0x09 : #charsetBackslashByte[i] = 't' ' tab
CASE 0x0B : #charsetBackslashByte[i] = 'v' ' vertical-tab
CASE 0x00 : #charsetBackslashByte[i] = '0' ' null
CASE ELSE : #charsetBackslashByte[i] = 0 ' non-simple backslash
END SELECT
NEXT i
'
'
' ************************************* \a \b \d \e \f \n \r \t \v
' ***** #charsetBackslashChar[] ***** \\ \"
' *************************************
'
' Return printable character intended to follow \ backslash character
' Return bytes that are normal, printable, non-backslash characters
'
FOR i = 0 TO 255
SELECT CASE i
CASE 0x5C : #charsetBackslashChar[i] = '\\' ' backslash
CASE 0x22 : #charsetBackslashChar[i] = '"' ' double-quote
CASE 0x07 : #charsetBackslashChar[i] = 'a' ' alarm (bell)
CASE 0x08 : #charsetBackslashChar[i] = 'b' ' backspace
CASE 0x7F : #charsetBackslashChar[i] = 'd' ' delete
CASE 0x1B : #charsetBackslashChar[i] = 'e' ' escape
CASE 0x0C : #charsetBackslashChar[i] = 'f' ' form-feed
CASE 0x0A : #charsetBackslashChar[i] = 'n' ' newline
CASE 0x0D : #charsetBackslashChar[i] = 'r' ' return
CASE 0x09 : #charsetBackslashChar[i] = 't' ' tab
CASE 0x0B : #charsetBackslashChar[i] = 'v' ' vertical-tab
CASE ELSE : #charsetBackslashChar[i] = 0 ' not a backslash char
END SELECT
NEXT i
'
'
' ********************************** 0x00 - 0x1F ===>> 0
' ***** #charsetNormalChar[] ***** 0x7F - 0xFF ===>> 0 (others unchanged)
' ********************************** \ and " ===>> 0
'
' Normal printable characters = the character, all others = 0
' NOTE: tab, newline, etc... not considered normal printable characters
' NOTE: backslash not considered normal printable character (need \\)
' NOTE: double-quote not considered normal printable character (need \")
'
FOR i = 0 TO 255
SELECT CASE TRUE
CASE (i <= 31) : #charsetNormalChar[i] = 0
CASE (i >= 127) : #charsetNormalChar[i] = 0
CASE (i = '\\') : #charsetNormalChar[i] = 0
CASE (i = '"') : #charsetNormalChar[i] = 0
CASE ELSE : #charsetNormalChar[i] = i
END SELECT
NEXT i
'
'
' ********************************* 0x00 - 0x1F ===>> 0
' ***** #charsetPrintChar[] ***** 0x7F - 0xFF ===>> 0
' ********************************* (others unchanged)
'
' Printable characters = the character, all others = 0
' NOTE: tab, newline, etc... not considered normal printable characters
' NOTE: backslash is a printable character
' NOTE: double-quote is a printable character
'
FOR i = 0 TO 255
SELECT CASE TRUE
CASE (i <= 31) : #charsetPrintChar[i] = 0
CASE (i >= 127) : #charsetPrintChar[i] = 0
CASE ELSE : #charsetPrintChar[i] = i
END SELECT
NEXT i
'
'
' ******************************
' ***** #charsetSuffix[] ***** valid type suffixes
' ******************************
'
#charsetSuffix['%'] = '%'
#charsetSuffix['&'] = '&'
#charsetSuffix['!'] = '!'
#charsetSuffix['#'] = '#'
#charsetSuffix['$'] = '$'
'
'
' ********************************
' ***** #charsetSpaceTab[] ***** only <space> and <tab> are true
' ********************************
'
#charsetSpaceTab[0x09] = 0x09 ' <tab> = '\t'
#charsetSpaceTab[0x20] = 0x20 ' <space> = ' '
'
'
' **********************************
' ***** #charsetWhitespace[] ***** all whitespace characters (space, tab, garbage)
' **********************************
'
FOR i = 0 TO 255
SELECT CASE TRUE
CASE (i <= 0x20) : #charsetWhitespace[i] = i ' from 0x00 to 0x20 (tab, space, trash)
CASE (i >= 0x80) : #charsetWhitespace[i] = i ' from 0x80 to 0xFF (unprintable trash)
END SELECT
NEXT i
END FUNCTION
'
'
' #######################################
' ##### InitializeQBasicTokens () #####
' #######################################
'
FUNCTION InitializeQBasicTokens ()
'
' define some shorthand variables
'
' common types
'
t0 = 0
tw = $$TYPE_SSHORT ' word
ti = $$TYPE_XLONG ' integer
tg = $$TYPE_GIANT ' giant-integer
tf = $$TYPE_DOUBLE ' floating-point
ts = $$TYPE_STRING ' nominal string
'
' common kinds
'
k0 = 0
ks = $$KIND_QBASIC | $$KIND_STATEMENT
ki = $$KIND_QBASIC | $$KIND_INTRINSIC
ko = $$KIND_QBASIC | $$KIND_OPERATOR
kk = $$KIND_QBASIC | $$KIND_KEYWORD
kt = $$KIND_QBASIC | $$KIND_TYPE
kl = $$KIND_QBASIC | $$KIND_LITERAL
kf = $$KIND_QBASIC | $$KIND_FUNCTION
ky = $$KIND_QBASIC | $$KIND_SYMBOL
kv = $$KIND_QBASIC | $$KIND_VARIABLE
ka = $$KIND_QBASIC | $$KIND_ARRAY
kc = $$KIND_QBASIC | $$KIND_COMPOSITE
ke = $$KIND_QBASIC | $$KIND_ELEMENT
kh = $$KIND_QBASIC | $$KIND_CHARACTER
kq = $$KIND_QBASIC
'
' common scopes
'
s0 = 0
sa = $$SCOPE_AUTO
sl = $$SCOPE_STATIC
ss = $$SCOPE_SHARED
se = $$SCOPE_EXTERNAL
'
q0 = 0
x0 = 0
'
'
' token_number = AddKeyword (translate, function, scope, kind, rtype, arg0, arg1, arg2, string$)
'
#qatoken = #ntoken + 1
#Q_ABS = AddKeyword (#X_ABS , f0, s0, ki, tf, tf, t0, t0, "ABS")
#Q_ABSOLUTE = AddKeyword ( x0, f0, s0, ki, tf, tf, t0, t0, "ABSOLUTE")
#Q_ACCESS = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "ACCESS")
#Q_ALIAS = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "ALIAS")
#Q_AND = AddKeyword (#X_AND , f0, s0, ko, t0, t0, t0, t0, "AND")
#Q_ANY = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "ANY")
#Q_APPEND = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "APPEND")
#Q_AS = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "AS")
#Q_ASC = AddKeyword (#X_ASC , f0, s0, ki, t0, t0, t0, t0, "ASC")
#Q_ATN = AddKeyword (#X_ATAN , f0, s0, ki, t0, t0, t0, t0, "ATN")
#Q_BASE = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "BASE")
#Q_BEEP = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "BEEP")
#Q_BINARY = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "BINARY")
#Q_BLOAD = AddKeyword ( x0, f0, s0, ks, t0, t0, t0, t0, "BLOAD")
#Q_BSAVE = AddKeyword ( x0, f0, s0, ks, t0, t0, t0, t0, "BSAVE")
#Q_BYVAL = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "BYVAL")
#Q_CALL = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "CALL")
#Q_CALLS = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "CALLS")
#Q_CASE = AddKeyword (#X_CASE , f0, s0, ks, t0, t0, t0, t0, "CASE")
#Q_CCUR = AddKeyword (#X_GIANT , f0, s0, ki, t0, t0, t0, t0, "CCUR")
#Q_CDBL = AddKeyword (#X_DOUBLE , f0, s0, ki, t0, t0, t0, t0, "CDBL")
#Q_CDECL = AddKeyword (#X_CFUNCTION , f0, s0, k0, t0, t0, t0, t0, "CDECL")
#Q_CHAIN = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "CHAIN")
#Q_CHDIR = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "CHDIR")
#Q_CHDRIVE = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "CHDRIVE")
#Q_CHR_D = AddKeyword (#X_CHR_D , f0, s0, ki, t0, t0, t0, t0, "CHR$")
#Q_CINT = AddKeyword (#X_SSHORT , f0, s0, ki, t0, t0, t0, t0, "CINT")
#Q_CIRCLE = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "CIRCLE")
#Q_CLEAR = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "CLEAR")
#Q_CLNG = AddKeyword (#X_SLONG , f0, s0, ki, t0, t0, t0, t0, "CLNG")
#Q_CLOSE = AddKeyword (#X_CLOSE , f0, s0, k0, t0, t0, t0, t0, "CLOSE")
#Q_CLS = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "CLS")
#Q_COLOR = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "COLOR")
#Q_COM = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "COM")
#Q_COMMAND_D = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "COMMAND$")
#Q_COMMON = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "COMMON")
#Q_CONST = AddKeyword ( x0, f0, s0, ks, t0, t0, t0, t0, "CONST")
#Q_COS = AddKeyword (#X_COS , f0, s0, ki, t0, t0, t0, t0, "COS")
#Q_CSNG = AddKeyword (#X_SINGLE , f0, s0, ki, t0, t0, t0, t0, "CSNG")
#Q_CSRLIN = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "CSRLIN")
#Q_CURDIR_D = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "CURDIR$")
#Q_CURRENCY = AddKeyword (#X_GIANT , f0, s0, k0, t0, t0, t0, t0, "CURRENCY")
#Q_CVC = AddKeyword (#X_GIANT , f0, s0, ki, t0, t0, t0, t0, "CVC")
#Q_CVD = AddKeyword (#X_DOUBLE , f0, s0, ki, t0, t0, t0, t0, "CVD")
#Q_CVI = AddKeyword (#X_SSHORT , f0, s0, ki, t0, t0, t0, t0, "CVI")
#Q_CVL = AddKeyword (#X_SLONG , f0, s0, ki, t0, t0, t0, t0, "CVL")
#Q_CVS = AddKeyword (#X_SINGLE , f0, s0, ki, t0, t0, t0, t0, "CVS")
#Q_CVSMBF = AddKeyword ( x0, f0, s0, ki, t0, t0, t0, t0, "CVSMBF")
#Q_DATA = AddKeyword ( x0, f0, s0, ks, t0, t0, t0, t0, "DATA")
#Q_DATE_D = AddKeyword ( x0, f0, s0, ki, t0, t0, t0, t0, "DATE$")
#Q_DECLARE = AddKeyword (#X_DECLARE , f0, s0, ks, t0, t0, t0, t0, "DECLARE")
#Q_DEF = AddKeyword ( x0, f0, s0, ks, t0, t0, t0, t0, "DEF")
#Q_DEFCUR = AddKeyword (#X_GIANT , f0, s0, ks, t0, t0, t0, t0, "DEFCUR")
#Q_DEFDBL = AddKeyword (#X_DOUBLE , f0, s0, ks, t0, t0, t0, t0, "DEFDBL")
#Q_DEFINT = AddKeyword (#X_SSHORT , f0, s0, ks, t0, t0, t0, t0, "DEFINT")
#Q_DEFLNG = AddKeyword (#X_SLONG , f0, s0, ks, t0, t0, t0, t0, "DEFLNG")
#Q_DEFSNG = AddKeyword (#X_SINGLE , f0, s0, ks, t0, t0, t0, t0, "DEFSNG")
#Q_DEFSTR = AddKeyword (#X_STRING , f0, s0, ks, t0, t0, t0, t0, "DEFSTR")
#Q_DELETE = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "DELETE")
#Q_DIM = AddKeyword (#X_DIM , f0, s0, ks, t0, t0, t0, t0, "DIM")
#Q_DIR_D = AddKeyword ( x0, f0, s0, ki, t0, t0, t0, t0, "DIR$")
#Q_DO = AddKeyword (#X_DO , f0, s0, ks, t0, t0, t0, t0, "DO")
#Q_DOUBLE = AddKeyword (#X_DOUBLE , f0, s0, k0, t0, t0, t0, t0, "DOUBLE")
#Q_DRAW = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "DRAW")
#Q_DYNAMIC = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "DYNAMIC")
#Q_ELSE = AddKeyword (#X_ELSE , f0, s0, ks, t0, t0, t0, t0, "ELSE")
#Q_ELSEIF = AddKeyword ( x0, f0, s0, ks, t0, t0, t0, t0, "ELSEIF")
#Q_END = AddKeyword (#X_END , f0, s0, ks, t0, t0, t0, t0, "END")
#Q_ENDIF = AddKeyword (#X_ENDIF , f0, s0, ks, t0, t0, t0, t0, "ENDIF")
#Q_ENVIRON = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "ENVIRON")
#Q_ENVIRON_D = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "ENVIRON$")
#Q_EOF = AddKeyword (#X_EOF , f0, s0, ki, t0, t0, t0, t0, "EOF")
#Q_EQV = AddKeyword ( x0, f0, s0, ko, t0, t0, t0, t0, "EQV")
#Q_ERASE = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "ERASE")
#Q_ERDEV = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "ERDEV")
#Q_ERDEV_D = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "ERDEV$")
#Q_ERL = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "ERL")
#Q_ERR = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "ERR")
#Q_ERROR = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "ERROR")
#Q_EVENT = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "EVENT")
#Q_EXIT = AddKeyword (#X_EXIT , f0, s0, ks, t0, t0, t0, t0, "EXIT")
#Q_EXP = AddKeyword (#X_EXP , f0, s0, ki, t0, t0, t0, t0, "EXP")
#Q_FIELD = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "FIELD")
#Q_FILEATTR = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "FILEATTR")
#Q_FILES = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "FILES")
#Q_FIX = AddKeyword (#X_FIX , f0, s0, ki, t0, t0, t0, t0, "FIX")
#Q_FN = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "FN")
#Q_FOR = AddKeyword (#X_FOR , f0, s0, ks, t0, t0, t0, t0, "FOR")
#Q_FRE = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "FRE")
#Q_FREEFILE = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "FREEFILE")
#Q_FUNCTION = AddKeyword (#X_FUNCTION , f0, s0, ks, t0, t0, t0, t0, "FUNCTION")
#Q_GET = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "GET")
#Q_GOSUB = AddKeyword (#X_GOSUB , f0, s0, ks, t0, t0, t0, t0, "GOSUB")
#Q_GOTO = AddKeyword (#X_GOTO , f0, s0, ks, t0, t0, t0, t0, "GOTO")
#Q_HEX_D = AddKeyword (#X_HEX_D , f0, s0, ki, t0, t0, t0, t0, "HEX$")
#Q_IF = AddKeyword (#X_IF , f0, s0, ks, t0, t0, t0, t0, "IF")
#Q_IMP = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "IMP")
#Q_INCLUDE = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "INCLUDE")
#Q_INKEY_D = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "INKEY$")
#Q_INP = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "INP")
#Q_INPUT = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "INPUT")
#Q_INPUT_D = AddKeyword (#X_INLINE_D , f0, s0, k0, t0, t0, t0, t0, "INPUT$")
#Q_INSTR = AddKeyword (#X_INSTR , f0, s0, ki, t0, t0, t0, t0, "INSTR")
#Q_INT = AddKeyword (#X_INT , f0, s0, ki, t0, t0, t0, t0, "INT")
#Q_INTEGER = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "INTEGER")
#Q_INTERRUPT = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "INTERRUPT")
#Q_IOCTL = AddKeyword ( x0, f0, s0, ki, t0, t0, t0, t0, "IOCTL")
#Q_IOCTL_D = AddKeyword ( x0, f0, s0, ki, t0, t0, t0, t0, "IOCTL$")
#Q_IS = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "IS")
#Q_KEY = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "KEY")
#Q_KILL = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "KILL")
#Q_LBOUND = AddKeyword ( x0, f0, s0, ki, t0, t0, t0, t0, "LBOUND")
#Q_LCASE_D = AddKeyword (#X_LCASE_D , f0, s0, ki, t0, t0, t0, t0, "LCASE$")
#Q_LEFT_D = AddKeyword (#X_LEFT_D , f0, s0, ki, t0, t0, t0, t0, "LEFT$")
#Q_LEN = AddKeyword (#X_LEN , f0, s0, ki, t0, t0, t0, t0, "LEN")
#Q_LET = AddKeyword ( x0, f0, s0, ks, t0, t0, t0, t0, "LET")
#Q_LINE = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "LINE")
#Q_LIST = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "LIST")
#Q_LOC = AddKeyword ( x0, f0, s0, ki, t0, t0, t0, t0, "LOC")
#Q_LOCAL = AddKeyword (#X_AUTO , f0, s0, k0, t0, t0, t0, t0, "LOCAL")
#Q_LOCATE = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "LOCATE")
#Q_LOCK = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "LOCK")
#Q_LOF = AddKeyword (#X_LOF , f0, s0, ki, t0, t0, t0, t0, "LOF")
#Q_LOG = AddKeyword (#X_LOG , f0, s0, ki, t0, t0, t0, t0, "LOG")
#Q_LONG = AddKeyword (#X_SLONG , f0, s0, k0, t0, t0, t0, t0, "LONG")
#Q_LOOP = AddKeyword (#X_LOOP , f0, s0, ks, t0, t0, t0, t0, "LOOP")
#Q_LPOS = AddKeyword ( x0, f0, s0, ki, t0, t0, t0, t0, "LPOS")
#Q_LPRINT = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "LPRINT")
#Q_LSET = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "LSET")
#Q_LTRIM_D = AddKeyword (#X_LTRIM_D , f0, s0, ki, t0, t0, t0, t0, "LTRIM$")
#Q_MID_D = AddKeyword (#X_MID_D , f0, s0, ki, t0, t0, t0, t0, "MID$")
#Q_MKC_D = AddKeyword (#X_STRING_D , f0, s0, ki, t0, t0, t0, t0, "MKC$")
#Q_MKDIR = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "MKDIR")
#Q_MKDMBF_D = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "MKDMBF$")
#Q_MKD_D = AddKeyword (#X_STRING_D , f0, s0, ki, t0, t0, t0, t0, "MKD$")
#Q_MKI_D = AddKeyword (#X_STRING_D , f0, s0, ki, t0, t0, t0, t0, "MKI$")
#Q_MKL_D = AddKeyword (#X_STRING_D , f0, s0, ki, t0, t0, t0, t0, "MKL$")
#Q_MKS_D = AddKeyword (#X_STRING_D , f0, s0, ki, t0, t0, t0, t0, "MKS$")
#Q_MKSMBF_D = AddKeyword ( x0, f0, s0, ki, t0, t0, t0, t0, "MKSMBF$")
#Q_MOD = AddKeyword (#X_MOD , f0, s0, ko, t0, t0, t0, t0, "MOD")
#Q_NAME = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "NAME")
#Q_NEXT = AddKeyword (#X_NEXT , f0, s0, ks, t0, t0, t0, t0, "NEXT")
#Q_NOT = AddKeyword (#X_NOT , f0, s0, ko, t0, t0, t0, t0, "NOT")
#Q_OCT_D = AddKeyword (#X_OCT_D , f0, s0, ki, t0, t0, t0, t0, "OCT$")
#Q_OFF = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "OFF")
#Q_ON = AddKeyword ( x0, f0, s0, ks, t0, t0, t0, t0, "ON")
#Q_OPEN = AddKeyword (#X_OPEN , f0, s0, k0, t0, t0, t0, t0, "OPEN")
#Q_OPTION = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "OPTION")
#Q_OR = AddKeyword (#X_OR , f0, s0, ko, t0, t0, t0, t0, "OR")
#Q_OUT = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "OUT")
#Q_OUTPUT = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "OUTPUT")
#Q_PAINT = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "PAINT")
#Q_PALETTE = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "PALETTE")
#Q_PCOPY = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "PCOPY")
#Q_PEEK = AddKeyword (#X_UBYTE_AT , f0, s0, ki, t0, t0, t0, t0, "PEEK")
#Q_PEN = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "PEN")
#Q_PLAY = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "PLAY")
#Q_PMAP = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "PMAP")
#Q_POINT = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "POINT")
#Q_POKE = AddKeyword (#X_UBYTE_AT , f0, s0, ks, t0, t0, t0, t0, "POKE")
#Q_POS = AddKeyword ( x0, f0, s0, ki, t0, t0, t0, t0, "POS")
#Q_PRESET = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "PRESET")
#Q_PRINT = AddKeyword (#X_PRINT , f0, s0, ks, t0, t0, t0, t0, "PRINT")
#Q_PSET = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "PSET")
#Q_PUT = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "PUT")
#Q_RANDOM = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "RANDOM")
#Q_RANDOMIZE = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "RANDOMIZE")
#Q_READ = AddKeyword (#X_READ , f0, s0, ks, t0, t0, t0, t0, "READ")
#Q_REDIM = AddKeyword (#X_REDIM , f0, s0, ks, t0, t0, t0, t0, "REDIM")
#Q_REM = AddKeyword (#X_REMARK , f0, s0, ks, t0, t0, t0, t0, "REM")
#Q_RESET = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "RESET")
#Q_RESTORE = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "RESTORE")
#Q_RESUME = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "RESUME")
#Q_RETURN = AddKeyword ( x0, f0, s0, ks, t0, t0, t0, t0, "RETURN")
#Q_RIGHT_D = AddKeyword (#X_RIGHT_D , f0, s0, ki, t0, t0, t0, t0, "RIGHT$")
#Q_RMDIR = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "RMDIR")
#Q_RND = AddKeyword ( x0, f0, s0, ki, t0, t0, t0, t0, "RND")
#Q_RSET = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "RSET")
#Q_RTRIM_D = AddKeyword (#X_RTRIM_D , f0, s0, ki, t0, t0, t0, t0, "RTRIM$")
#Q_RUN = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "RUN")
#Q_SADD = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "SADD")
#Q_SCREEN = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "SCREEN")
#Q_SEEK = AddKeyword (#X_SEEK , f0, s0, ki, t0, t0, t0, t0, "SEEK")
#Q_SEG = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "SEG")
#Q_SELECT = AddKeyword (#X_SELECT , f0, s0, ks, t0, t0, t0, t0, "SELECT")
#Q_SETMEM = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "SETMEM")
#Q_SGN = AddKeyword (#X_SGN , f0, s0, ki, t0, t0, t0, t0, "SGN")
#Q_SHARED = AddKeyword (#X_SHARED , f0, s0, ks, t0, t0, t0, t0, "SHARED")
#Q_SHELL = AddKeyword (#X_SHELL , f0, s0, k0, t0, t0, t0, t0, "SHELL")
#Q_SIGNAL = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "SIGNAL")
#Q_SIN = AddKeyword (#X_SIN , f0, s0, ki, t0, t0, t0, t0, "SIN")
#Q_SINGLE = AddKeyword (#X_SINGLE , f0, s0, ks, t0, t0, t0, t0, "SINGLE")
#Q_SLEEP = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "SLEEP")
#Q_SOUND = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "SOUND")
#Q_SPACE_D = AddKeyword (#X_SPACE_D , f0, s0, ki, t0, t0, t0, t0, "SPACE$")
#Q_SPC = AddKeyword ( x0, f0, s0, ki, t0, t0, t0, t0, "SPC")
#Q_SQR = AddKeyword (#X_SQRT , f0, s0, ki, t0, t0, t0, t0, "SQR")
#Q_SSEG = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "SSEG")
#Q_SSEGADD = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "SSEGADD")
#Q_STACK = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "STACK")
#Q_STATIC = AddKeyword (#X_STATIC , f0, s0, ks, t0, t0, t0, t0, "STATIC")
#Q_STEP = AddKeyword (#X_STEP , f0, s0, ks, t0, t0, t0, t0, "STEP")
#Q_STICK = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "STICK")
#Q_STOP = AddKeyword (#X_STOP , f0, s0, ks, t0, t0, t0, t0, "STOP")
#Q_STR_D = AddKeyword (#X_STR_D , f0, s0, ki, t0, t0, t0, t0, "STR$")
#Q_STRIG = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "STRIG")
#Q_STRING = AddKeyword (#X_STRING , f0, s0, k0, t0, t0, t0, t0, "STRING")
#Q_STRING_D = AddKeyword (#X_CHR_D , f0, s0, ki, t0, t0, t0, t0, "STRING$")
#Q_SUB = AddKeyword (#X_FUNCTION , f0, s0, ks, t0, t0, t0, t0, "SUB")
#Q_SWAP = AddKeyword (#X_SWAP , f0, s0, ks, t0, t0, t0, t0, "SWAP")
#Q_SYSTEM = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "SYSTEM")
#Q_TAB = AddKeyword (#X_TAB , f0, s0, ki, t0, t0, t0, t0, "TAB")
#Q_TAN = AddKeyword (#X_TAN , f0, s0, ki, t0, t0, t0, t0, "TAN")
#Q_THEN = AddKeyword (#X_THEN , f0, s0, ks, t0, t0, t0, t0, "THEN")
#Q_TIME_D = AddKeyword ( x0, f0, s0, ki, t0, t0, t0, t0, "TIME$")
#Q_TIMER = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "TIMER")
#Q_TO = AddKeyword (#X_TO , f0, s0, ks, t0, t0, t0, t0, "TO")
#Q_TROFF = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "TROFF")
#Q_TRON = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "TRON")
#Q_TYPE = AddKeyword (#X_TYPE , f0, s0, ks, t0, t0, t0, t0, "TYPE")
#Q_UBOUND = AddKeyword (#X_UBOUND , f0, s0, ki, t0, t0, t0, t0, "UBOUND")
#Q_UCASE_D = AddKeyword (#X_UCASE_D , f0, s0, ki, t0, t0, t0, t0, "UCASE$")
#Q_UEVENT = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "UEVENT")
#Q_UNLOCK = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "UNLOCK")
#Q_UNTIL = AddKeyword (#X_UNTIL , f0, s0, ks, t0, t0, t0, t0, "UNTIL")
#Q_UPDATE = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "UPDATE")
#Q_USING = AddKeyword (#X_FORMAT_D , f0, s0, ks, t0, t0, t0, t0, "USING")
#Q_VAL = AddKeyword (#X_DOUBLE , f0, s0, ki, t0, t0, t0, t0, "VAL")
#Q_VARPTR = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "VARPTR")
#Q_VARPTR_D = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "VARPTR$")
#Q_VARSEG = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "VARSEG")
#Q_VIEW = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "VIEW")
#Q_WAIT = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "WAIT")
#Q_WEND = AddKeyword (#X_LOOP , f0, s0, ks, t0, t0, t0, t0, "WEND")
#Q_WHILE = AddKeyword (#X_DO , f0, s0, ks, t0, t0, t0, t0, "WHILE")
#Q_WIDTH = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "WIDTH")
#Q_WINDOW = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "WINDOW")
#Q_WRITE = AddKeyword (#X_WRITE , f0, s0, ks, t0, t0, t0, t0, "WRITE")
#Q_XOR = AddKeyword (#X_XOR , f0, s0, ko, t0, t0, t0, t0, "XOR")
'
' #Q_POST_SSHORT = AddKeyword (#X_POST_SSHORT, f0, s0, kc, 4, t0, t0, t0, "%") ' part of string ???
' #Q_POST_SLONG = AddKeyword (#X_POST_SLONG , f0, s0, kc, 6, t0, t0, t0, "&") ' part of string ???
' #Q_POST_SINGLE = AddKeyword (#X_POST_SINGLE, f0, s0, kc, 13, t0, t0, t0, "!") ' part of string ???
' #Q_POST_DOUBLE = AddKeyword (#X_POST_DOUBLE, f0, s0, kc, 14, t0, t0, t0, "#") ' part of string ???
' #Q_POST_STRING = AddKeyword (#X_POST_STRING, f0, s0, kc, 15, t0, t0, t0, "$") ' part of string ???
'
#Q_PLUS = AddKeyword (#X_PLUS , f0, s0, ko, t0, t0, t0, t0, "+") ' unary
#Q_MINUS = AddKeyword (#X_MINUS , f0, s0, ko, t0, t0, t0, t0, "-") ' unary
' #Q_ADDRESS = AddKeyword ( q0, f0, s0, ko, t0, t0, t0, t0, "&") ' unary
'
#Q_ADD = AddKeyword (#X_ADD , f0, s0, ko, t0, t0, t0, t0, "+")
#Q_SUBTRACT = AddKeyword (#X_SUBTRACT , f0, s0, ko, t0, t0, t0, t0, "-")
#Q_MULTIPLY = AddKeyword (#X_MULTIPLY , f0, s0, ko, t0, t0, t0, t0, "*")
#Q_DIVIDE = AddKeyword (#X_DIVIDE , f0, s0, ko, t0, t0, t0, t0, "/")
#Q_POWER = AddKeyword (#X_POWER , f0, s0, ko, t0, t0, t0, t0, "^")
#Q_IDIVIDE = AddKeyword (#X_IDIVIDE , f0, s0, ko, t0, t0, t0, t0, "\\")
#Q_REMAINDER = AddKeyword (#X_MOD , f0, s0, ko, t0, t0, t0, t0, "%")
'
#Q_NOTBIT = AddKeyword (#X_NOT , f0, s0, ko, t0, t0, t0, t0, "~") ' unary
#Q_ANDBIT = AddKeyword (#X_AND , f0, s0, ko, t0, t0, t0, t0, "&")
#Q_ORBIT = AddKeyword (#X_OR , f0, s0, ko, t0, t0, t0, t0, "|")
#Q_EQ = AddKeyword (#X_EQ , f0, s0, ko, t0, t0, t0, t0, "=")
#Q_NE = AddKeyword (#X_NE , f0, s0, ko, t0, t0, t0, t0, "<>")
#Q_LT = AddKeyword (#X_LT , f0, s0, ko, t0, t0, t0, t0, "<")
#Q_LE = AddKeyword (#X_LE , f0, s0, ko, t0, t0, t0, t0, "<=")
#Q_GE = AddKeyword (#X_GE , f0, s0, ko, t0, t0, t0, t0, ">=")
#Q_GT = AddKeyword (#X_GT , f0, s0, ko, t0, t0, t0, t0, ">")
'
#Q_LPAREN = AddKeyword (#X_LPAREN , f0, s0, kc, t0, t0, t0, t0, "(")
#Q_RPAREN = AddKeyword (#X_RPAREN , f0, s0, kc, t0, t0, t0, t0, ")")
#Q_LBRAK = AddKeyword (#X_LBRAK , f0, s0, kc, t0, t0, t0, t0, "[")
#Q_RBRAK = AddKeyword (#X_RBRAK , f0, s0, kc, t0, t0, t0, t0, "]")
#Q_COMMA = AddKeyword (#X_COMMA , f0, s0, kc, t0, t0, t0, t0, ",")
#Q_COLON = AddKeyword (#X_COLON , f0, s0, kc, t0, t0, t0, t0, ":")
#Q_SEMI = AddKeyword (#X_SEMI , f0, s0, kc, t0, t0, t0, t0, ";")
'
' #Q_KEYWORD = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "")
' #Q_KEYWORD = AddKeyword ( x0, f0, s0, k0, t0, t0, t0, t0, "")
#qztoken = #ntoken
END FUNCTION
'
'
' #######################################
' ##### InitializeXBasicTokens () #####
' #######################################
'
FUNCTION InitializeXBasicTokens ()
'
' define shorthand variables to make function calls readable
'
' common data-types
'
t0 = 0
ti = $$TYPE_XLONG ' integer
tg = $$TYPE_GIANT ' giant-integer
tf = $$TYPE_DOUBLE ' floating-point
ts = $$TYPE_STRING ' nominal string
'
' common kinds
'
k0 = 0
ks = $$KIND_XBASIC | $$KIND_STATEMENT
ki = $$KIND_XBASIC | $$KIND_INTRINSIC
ko = $$KIND_XBASIC | $$KIND_OPERATOR
kk = $$KIND_XBASIC | $$KIND_KEYWORD
kt = $$KIND_XBASIC | $$KIND_TYPE
kl = $$KIND_XBASIC | $$KIND_LITERAL
kf = $$KIND_XBASIC | $$KIND_FUNCTION
ky = $$KIND_XBASIC | $$KIND_SYMBOL
kv = $$KIND_XBASIC | $$KIND_VARIABLE
ka = $$KIND_XBASIC | $$KIND_ARRAY
kc = $$KIND_XBASIC | $$KIND_COMPOSITE
ke = $$KIND_XBASIC | $$KIND_ELEMENT
kh = $$KIND_XBASIC | $$KIND_CHARACTER
km = $$KIND_XBASIC | $$KIND_FUNCTION ' math library functions look like intrinsics
kx = $$KIND_XBASIC
'
' common kinds
'
s0 = 0
sa = $$SCOPE_AUTO
sx = $$SCOPE_AUTOX
sl = $$SCOPE_STATIC
ss = $$SCOPE_SHARED
se = $$SCOPE_EXTERNAL
'
q0 = 0
x0 = 0
'
'
' token_number = AddKeyword (translate, function, scope, kind, rtype, arg0, arg1, arg2, string$)
'
#xatoken = #ntoken + 1
#X_ABS = AddKeyword (#Q_ABS , f0, s0, ki, tf, tf, t0, t0, "ABS")
#X_ALL = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "ALL")
#X_AND = AddKeyword (#Q_AND , f0, s0, ko, t0, t0, t0, t0, "AND")
#X_ANY = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "ANY")
#X_ASC = AddKeyword (#Q_ASC , f0, s0, ki, t0, t0, t0, t0, "ASC")
#X_ATAN = AddKeyword (#Q_ATN , f0, s0, km, t0, t0, t0, t0, "ATAN")
#X_ATTACH = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "ATTACH")
#X_AUTO = AddKeyword ( q0, f0, sa, ks, t0, t0, t0, t0, "AUTO")
#X_AUTOX = AddKeyword ( q0, f0, sx, ks, t0, t0, t0, t0, "AUTOX")
#X_BIN_D = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "BIN$")
#X_BINB_D = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "BINB$")
#X_BITFIELD = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "BITFIELD")
#X_CASE = AddKeyword (#Q_CASE , f0, s0, ks, t0, t0, t0, t0, "CASE")
#X_CFUNCTION = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "CFUNCTION")
#X_CHR_D = AddKeyword (#Q_CHR_D , f0, s0, ki, t0, t0, t0, t0, "CHR$")
#X_CJUST_D = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "CJUST$")
#X_CLOSE = AddKeyword (#Q_CLOSE , f0, s0, ki, t0, t0, t0, t0, "CLOSE")
#X_CLR = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "CLR")
#X_CSIZE = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "CSIZE")
#X_CSIZE_D = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "CSIZE$")
#X_CSTRING_D = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "CSTRING$")
#X_DEC = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "DEC")
#X_DECLARE = AddKeyword (#Q_DECLARE , f0, s0, ks, t0, t0, t0, t0, "DECLARE")
#X_DHIGH = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "DHIGH")
#X_DIM = AddKeyword (#Q_DIM , f0, s0, ki, t0, t0, t0, t0, "DIM")
#X_DLOW = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "DLOW")
#X_DMAKE = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "DMAKE")
#X_DO = AddKeyword (#Q_DO , f0, s0, ks, t0, t0, t0, t0, "DO")
#X_DOUBLE = AddKeyword (#Q_DOUBLE , f0, s0, ks, t0, t0, t0, t0, "DOUBLE")
#X_DOUBLE = AddKeyword (#Q_DOUBLE , f0, s0, ki, t0, t0, t0, t0, "DOUBLE")
#X_DOUBLEAT = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "DOUBLEAT")
#X_ELSE = AddKeyword (#Q_ELSE , f0, s0, ks, t0, t0, t0, t0, "ELSE")
#X_END = AddKeyword (#Q_END , f0, s0, ks, t0, t0, t0, t0, "END")
#X_ENDIF = AddKeyword (#Q_ENDIF , f0, s0, ks, t0, t0, t0, t0, "ENDIF")
#X_EOF = AddKeyword (#Q_EOF , f0, s0, ki, t0, t0, t0, t0, "EOF")
#X_ERROR = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "ERROR")
#X_EXIT = AddKeyword (#Q_EXIT , f0, s0, ks, t0, t0, t0, t0, "EXIT")
#X_EXP = AddKeyword (#Q_EXP , f0, s0, km, t0, t0, t0, t0, "EXP")
#X_EXTERNAL = AddKeyword ( q0, f0, se, ks, t0, t0, t0, t0, "EXTERNAL")
#X_EXTS = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "EXTS")
#X_EXTU = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "EXTU")
#X_FALSE = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "FALSE")
#X_FIX = AddKeyword (#Q_FIX , f0, s0, ki, t0, t0, t0, t0, "FIX")
#X_FOR = AddKeyword (#Q_FOR , f0, s0, ks, t0, t0, t0, t0, "FOR")
#X_FORMAT_D = AddKeyword (#Q_USING , f0, s0, ki, t0, t0, t0, t0, "FORMAT$")
#X_FUNCADDR = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "FUNCADDR")
#X_FUNCADDR = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "FUNCADDR")
#X_FUNCADDRAT = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "FUNCADDRAT")
#X_FUNCADDRESS = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "FUNCADDRESS")
#X_FUNCTION = AddKeyword (#Q_FUNCTION , f0, s0, ks, t0, t0, t0, t0, "FUNCTION")
#X_GHIGH = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "GHIGH")
#X_GIANT = AddKeyword (#Q_GIANT , f0, s0, ks, t0, t0, t0, t0, "GIANT")
#X_GIANT = AddKeyword (#Q_GIANT , f0, s0, ki, t0, t0, t0, t0, "GIANT")
#X_GIANTAT = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "GIANTAT")
#X_GLOW = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "GLOW")
#X_GMAKE = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "GMAKE")
#X_GOADDR = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "GOADDR")
#X_GOADDR = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "GOADDR")
#X_GOADDRAT = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "GOADDRAT")
#X_GOADDRESS = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "GOADDRESS")
#X_GOSUB = AddKeyword (#Q_GOSUB , f0, s0, ks, t0, t0, t0, t0, "GOSUB")
#X_GOTO = AddKeyword (#Q_GOTO , f0, s0, ks, t0, t0, t0, t0, "GOTO")
#X_HEX_D = AddKeyword (#Q_HEX_D , f0, s0, ki, t0, t0, t0, t0, "HEX$")
#X_HEXX_D = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "HEXX$")
#X_HIGH0 = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "HIGH0")
#X_HIGH1 = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "HIGH1")
#X_IF = AddKeyword (#Q_IF , f0, s0, ks, t0, t0, t0, t0, "IF")
#X_IFF = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "IFF")
#X_IFT = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "IFT")
#X_IFZ = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "IFZ")
#X_INC = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "INC")
#X_INCHR = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "INCHR")
#X_INCHRI = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "INCHRI")
#X_INT = AddKeyword (#Q_INT , f0, s0, ki, t0, t0, t0, t0, "INT")
#X_INTERNAL = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "INTERNAL")
#X_LCASE_D = AddKeyword (#Q_LCASE_D , f0, s0, ki, t0, t0, t0, t0, "LCASE$")
#X_LCLIP_D = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "LCLIP$")
#X_LEFT_D = AddKeyword (#Q_LEFT_D , f0, s0, ki, t0, t0, t0, t0, "LEFT$")
#X_LEN = AddKeyword (#Q_LEN , f0, s0, ki, t0, t0, t0, t0, "LEN")
#X_LJUST_D = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "LJUST$")
#X_LOF = AddKeyword (#Q_LOF , f0, s0, ki, t0, t0, t0, t0, "LOF")
#X_LOG = AddKeyword (#Q_LOG , f0, s0, km, t0, t0, t0, t0, "LOG")
#X_LOOP = AddKeyword (#Q_LOOP , f0, s0, ks, t0, t0, t0, t0, "LOOP")
#X_LTRIM_D = AddKeyword (#Q_LTRIM_D , f0, s0, ki, t0, t0, t0, t0, "LTRIM$")
#X_MAKE = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "MAKE")
#X_MAX = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "MAX")
#X_MID_D = AddKeyword (#Q_MID_D , f0, s0, ki, t0, t0, t0, t0, "MID$")
#X_MIN = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "MIN")
#X_MOD = AddKeyword (#Q_MOD , f0, s0, ko, t0, t0, t0, t0, "MOD")
#X_NEXT = AddKeyword (#Q_NEXT , f0, s0, ks, t0, t0, t0, t0, "NEXT")
#X_NOT = AddKeyword (#Q_NOT , f0, s0, ko, t0, t0, t0, t0, "NOT")
#X_NULL_D = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "NULL$")
#X_OCT_D = AddKeyword (#Q_OCT_D , f0, s0, ki, t0, t0, t0, t0, "OCT$")
#X_OCTO_D = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "OCTO$")
#X_OPEN = AddKeyword (#Q_OPEN , f0, s0, ki, t0, t0, t0, t0, "OPEN")
#X_OR = AddKeyword (#Q_OR , f0, s0, ko, t0, t0, t0, t0, "OR")
#X_POF = AddKeyword (#Q_POF , f0, s0, ki, t0, t0, t0, t0, "POF")
#X_PRINT = AddKeyword (#Q_PRINT , f0, s0, ks, t0, t0, t0, t0, "PRINT")
#X_PROGRAM = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "PROGRAM")
#X_QUIT = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "QUIT")
#X_RCLIP_D = AddKeyword (#Q_RCLIP_D , f0, s0, ki, t0, t0, t0, t0, "RCLIP$")
#X_READ = AddKeyword (#Q_READ , f0, s0, ks, t0, t0, t0, t0, "READ")
#X_REDIM = AddKeyword (#Q_REDIM , f0, s0, ks, t0, t0, t0, t0, "REDIM")
#X_RETURN = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "RETURN")
#X_RIGHT_D = AddKeyword (#Q_RIGHT_D , f0, s0, ki, t0, t0, t0, t0, "RIGHT$")
#X_RINCHR = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "RINCHR")
#X_RINCHRI = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "RINCHRI")
#X_RINSTR = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "RINSTR")
#X_RINSTRI = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "RINSTRI")
#X_RJUST_D = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "RJUST$")
#X_ROTATER = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "ROTATER")
#X_RTRIM_D = AddKeyword (#Q_RTRIM_D , f0, s0, ki, t0, t0, t0, t0, "RTRIM$")
#X_SBYTE = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "SBYTE")
#X_SBYTE = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "SBYTE")
#X_SBYTEAT = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "SBYTEAT")
#X_SEEK = AddKeyword (#Q_SEEK , f0, s0, ki, t0, t0, t0, t0, "SEEK")
#X_SELECT = AddKeyword (#Q_SELECT , f0, s0, ks, t0, t0, t0, t0, "SELECT")
#X_SET = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "SET")
#X_SGN = AddKeyword (#Q_SGN , f0, s0, ki, t0, t0, t0, t0, "SGN")
#X_SFUNCTION = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "SFUNCTION")
#X_SHARED = AddKeyword (#Q_SHARED , f0, s0, ks, t0, t0, t0, t0, "SHARED")
#X_SHELL = AddKeyword (#Q_SHELL , f0, ss, ki, t0, t0, t0, t0, "SHELL")
#X_SIGN = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "SIGN")
#X_SIGNED_D = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "SIGNED$")
#X_SIN = AddKeyword (#Q_SIN , f0, s0, km, t0, t0, t0, t0, "SIN")
#X_SINGLE = AddKeyword (#Q_SINGLE , f0, s0, ks, t0, t0, t0, t0, "SINGLE")
#X_SINGLE = AddKeyword (#Q_SINGLE , f0, s0, ki, t0, t0, t0, t0, "SINGLE")
#X_SINGLEAT = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "SINGLEAT")
#X_SIZE = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "SIZE")
#X_SLONG = AddKeyword (#Q_LONG , f0, s0, ks, t0, t0, t0, t0, "SLONG")
#X_SLONG = AddKeyword (#Q_LONG , f0, s0, ki, t0, t0, t0, t0, "SLONG")
#X_SLONGAT = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "SLONGAT")
#X_SMAKE = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "SMAKE")
#X_SPACE_D = AddKeyword (#Q_SPACE_D , f0, s0, ki, t0, t0, t0, t0, "SPACE$")
#X_SSHORT = AddKeyword (#Q_SHORT , f0, s0, ks, t0, t0, t0, t0, "SSHORT")
#X_SSHORT = AddKeyword (#Q_SHORT , f0, s0, ki, t0, t0, t0, t0, "SSHORT")
#X_SSHORTAT = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "SSHORTAT")
#X_SQRT = AddKeyword (#Q_INTEGER , f0, s0, km, t0, t0, t0, t0, "SQRT")
#X_STATIC = AddKeyword (#Q_STATIC , f0, sl, ks, t0, t0, t0, t0, "STATIC")
#X_STEP = AddKeyword (#Q_STEP , f0, s0, ks, t0, t0, t0, t0, "STEP")
#X_STOP = AddKeyword (#Q_STOP , f0, s0, ks, t0, t0, t0, t0, "STOP")
#X_STR_D = AddKeyword (#Q_STR_D , f0, s0, ki, t0, t0, t0, t0, "STR$")
#X_STRING = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "STRING")
#X_STRING = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "STRING")
#X_STRING_D = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "STRING$")
#X_STUFF_D = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "STUFF$")
#X_SUB = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "SUB")
#X_SUBADDR = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "SUBADDR")
#X_SUBADDR = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "SUBADDR")
#X_SUBADDRAT = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "SUBADDRAT")
#X_SUBADDRESS = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "SUBADDRESS")
#X_SWAP = AddKeyword (#Q_SWAP , f0, s0, ki, t0, t0, t0, t0, "SWAP")
#X_TAB = AddKeyword (#Q_TAB , f0, s0, ki, t0, t0, t0, t0, "TAB")
#X_TAN = AddKeyword (#Q_TAN , f0, s0, km, t0, t0, t0, t0, "TAN")
#X_THEN = AddKeyword (#Q_THEN , f0, s0, ks, t0, t0, t0, t0, "THEN")
#X_TO = AddKeyword (#Q_TO , f0, s0, ks, t0, t0, t0, t0, "TO")
#X_TRIM_D = AddKeyword (#Q_TRIM_D , f0, s0, ki, t0, t0, t0, t0, "TRIM$")
#X_TYPE = AddKeyword (#Q_TYPE , f0, s0, ks, t0, t0, t0, t0, "TYPE")
#X_UBOUND = AddKeyword (#Q_UBOUND , f0, s0, ki, t0, t0, t0, t0, "UBOUND")
#X_UBYTE = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "UBYTE")
#X_UBYTE = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "UBYTE")
#X_UBYTEAT = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "UBYTEAT")
#X_UCASE_D = AddKeyword (#Q_UCASE_D , f0, s0, ki, t0, t0, t0, t0, "UCASE$")
#X_ULONG = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "ULONG")
#X_ULONG = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "ULONG")
#X_ULONGAT = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "ULONGAT")
#X_UNION = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "UNION")
#X_UNTIL = AddKeyword (#Q_UNTIL , f0, s0, ks, t0, t0, t0, t0, "UNTIL")
#X_USHORT = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "USHORT")
#X_USHORT = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "USHORT")
#X_USHORTAT = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "USHORTAT")
#X_VOID = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "VOID")
#X_WHILE = AddKeyword (#Q_WHILE , f0, s0, ks, t0, t0, t0, t0, "WHILE")
#X_WRITE = AddKeyword (#Q_WRITE , f0, s0, ks, t0, t0, t0, t0, "WRITE")
#X_XLONG = AddKeyword ( q0, f0, s0, ks, t0, t0, t0, t0, "XLONG")
#X_XLONG = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "XLONG")
#X_XLONGAT = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "XLONGAT")
#X_XMAKE = AddKeyword ( q0, f0, s0, ki, t0, t0, t0, t0, "XMAKE")
#X_XOR = AddKeyword (#Q_XOR , f0, s0, ko, t0, t0, t0, t0, "XOR")
'
#X_PRE_BYREF = AddKeyword ( q0, f0, s0, kh, t0, t0, t0, t0, "@")
#X_PRE_SHARED = AddKeyword ( q0, f0, s5, kh, t0, t0, t0, t0, "#")
#X_PRE_EXTERNAL = AddKeyword ( q0, f0, s7, kh, t0, t0, t0, t0, "##")
'
' #X_POST_SBYTE = AddKeyword ( q0, f0, s0, kh, 2, t0, t0, t0, "@") ' part of symbol
' #X_POST_UBYTE = AddKeyword ( q0, f0, s0, kh, 3, t0, t0, t0, "@@") ' part of symbol
' #X_POST_SSHORT = AddKeyword (#Q_POST_SSHORT, f0, s0, kh, 4, t0, t0, t0, "%") ' part of symbol
' #X_POST_USHORT = AddKeyword ( q0, f0, s0, kh, 5, t0, t0, t0, "%%") ' part of symbol
' #X_POST_SLONG = AddKeyword (#Q_POST_SLONG , f0, s0, kh, 6, t0, t0, t0, "&") ' part of symbol
' #X_POST_ULONG = AddKeyword ( q0, f0, s0, kh, 7, t0, t0, t0, "&&") ' part of symbol
' #X_POST_XLONG = AddKeyword ( q0, f0, s0, kh, 8, t0, t0, t0, "~") ' part of symbol
' #X_POST_GIANT = AddKeyword ( q0, f0, s0, kh, 12, t0, t0, t0, "$$") ' part of symbol
' #X_POST_SINGLE = AddKeyword (#Q_POST_SINGLE, f0, s0, kh, 13, t0, t0, t0, "!") ' part of symbol
' #X_POST_DOUBLE = AddKeyword (#Q_POST_DOUBLE, f0, s0, kh, 14, t0, t0, t0, "#") ' part of symbol
' #X_POST_STRING = AddKeyword (#Q_POST_STRING, f0, s0, kh, 15, t0, t0, t0, "$") ' part of symbol
'
#X_PLUS = AddKeyword (#Q_PLUS , f0, s0, ko, t0, t0, t0, t0, "+") ' unary
#X_MINUS = AddKeyword (#Q_MINUS , f0, s0, ko, t0, t0, t0, t0, "-") ' unary
#X_ADDRESS = AddKeyword ( q0, f0, s0, ko, t0, t0, t0, t0, "&") ' unary
'
#X_ADD = AddKeyword (#Q_ADD , f0, s0, ko, t0, t0, t0, t0, "+")
#X_SUBTRACT = AddKeyword (#Q_SUBTRACT , f0, s0, ko, t0, t0, t0, t0, "-")
#X_MULTIPLY = AddKeyword (#Q_MULTIPLY , f0, s0, ko, t0, t0, t0, t0, "*")
#X_DIVIDE = AddKeyword (#Q_DIVIDE , f0, s0, ko, t0, t0, t0, t0, "/")
#X_POWER = AddKeyword (#Q_POWER , f0, s0, ko, t0, t0, t0, t0, "**")
#X_IDIVIDE = AddKeyword (#Q_IDIVIDE , f0, s0, ko, t0, t0, t0, t0, "\\")
#X_REMAINDER = AddKeyword (#Q_MOD , f0, s0, ko, t0, t0, t0, t0, "%")
'
#X_USHIFT = AddKeyword ( q0, f0, s0, ko, t0, t0, t0, t0, "<<<")
#X_DSHIFT = AddKeyword ( q0, f0, s0, ko, t0, t0, t0, t0, ">>>")
#X_LSHIFT = AddKeyword ( q0, f0, s0, ko, t0, t0, t0, t0, "<<")
#X_RSHIFT = AddKeyword ( q0, f0, s0, ko, t0, t0, t0, t0, ">>")
#X_NOTBIT = AddKeyword (#Q_NOT , f0, s0, ko, t0, t0, t0, t0, "~")
#X_ANDBIT = AddKeyword (#Q_AND , f0, s0, ko, t0, t0, t0, t0, "&")
#X_ORBIT = AddKeyword (#Q_OR , f0, s0, ko, t0, t0, t0, t0, "|")
#X_TESTL = AddKeyword ( q0, f0, s0, ko, t0, t0, t0, t0, "!!")
#X_NOTL = AddKeyword ( q0, f0, s0, ko, t0, t0, t0, t0, "!")
#X_ANDL = AddKeyword ( q0, f0, s0, ko, t0, t0, t0, t0, "&&")
#X_XORL = AddKeyword ( q0, f0, s0, ko, t0, t0, t0, t0, "^^")
#X_ORL = AddKeyword ( q0, f0, s0, ko, t0, t0, t0, t0, "||")
#X_EQ = AddKeyword (#Q_EQ , f0, s0, ko, t0, t0, t0, t0, "=")
#X_NE = AddKeyword (#Q_NE , f0, s0, ko, t0, t0, t0, t0, "<>")
#X_LT = AddKeyword (#Q_LT , f0, s0, ko, t0, t0, t0, t0, "<")
#X_LE = AddKeyword (#Q_LE , f0, s0, ko, t0, t0, t0, t0, "<=")
#X_GE = AddKeyword (#Q_GE , f0, s0, ko, t0, t0, t0, t0, ">=")
#X_GT = AddKeyword (#Q_GT , f0, s0, ko, t0, t0, t0, t0, ">")
#X_EQU = AddKeyword (#Q_EQ , f0, s0, ko, t0, t0, t0, t0, "==")
#X_NEQ = AddKeyword (#Q_NE , f0, s0, ko, t0, t0, t0, t0, "!=")
#X_NGE = AddKeyword (#Q_LT , f0, s0, ko, t0, t0, t0, t0, "!>=")
#X_NGT = AddKeyword (#Q_LE , f0, s0, ko, t0, t0, t0, t0, "!>")
#X_NLE = AddKeyword (#Q_GE , f0, s0, ko, t0, t0, t0, t0, "!<")
#X_NLT = AddKeyword (#Q_GT , f0, s0, ko, t0, t0, t0, t0, "!<=")
'
' #X_KEYWORD = AddKeyword ( q0, f0, s0, k0, t0, t0, t0, t0, "")
' #X_KEYWORD = AddKeyword ( q0, f0, s0, k0, t0, t0, t0, t0, "")
#xztoken = #ntoken
END FUNCTION
'
'
' ##################################
' ##### LoadQBasicProgram () #####
' ##################################
'
FUNCTION LoadQBasicProgram (@qbasic$[])
'
DIM qbasic$[] ' empty qbasic$[]
' print = $$TRUE ' print for debugging
XstGetCommandLineArguments (@count, @arg$[]) ' arg$[1] = QBasic program filename
'
' input filename of QBasic program if no command line argument
'
IF (count < 2) THEN
qfile$ = INLINE$ ("input filename of QuickBasic file ===>> ")
IFZ qfile$ THEN qfile$ = "qbasic.bas"
ELSE
qfile$ = arg$[1]
END IF
'
' qfile$ = filename of QBasic program - must be ASCII
'
IFZ qbasic$[] THEN
XstLoadStringArray (@qfile$, @qbasic$[]) ' qbasic$[] = QBasic program
END IF
'
IFZ qbasic$[] THEN
dot = RINSTR (qfile$, ".")
IF dot THEN file$ = LEFT$ (qfile$, dot-1)
END IF
'
IFZ qbasic$[] THEN
qfile$ = file$ + ".bas"
XstLoadStringArray (@qfile$, @qbasic$[]) ' qbasic$[] = QBasic program
END IF
'
IFZ qbasic$[] THEN
qfile$ = file$ + ".x"
XstLoadStringArray (@qfile$, @qbasic$[]) ' qbasic$[] = QBasic program
END IF
'
' print QBasic program during testing
'
uline = UBOUND (qbasic$[]) ' upper bound of QBasic array
FOR line = 0 TO uline ' for all lines of QBasic source
line$ = RTRIM$(qbasic$[line]) ' line$ = next line of QBasic program
IF line$ THEN topline = line ' this could be the final QBasic line
IF print THEN PRINT line$ ' perhaps print the QBasic line
qbasic$[line] = line$ ' replace trimmed line
NEXT line
'
IF (topline != uline) THEN REDIM qbasic$[topline]
END FUNCTION
'
'
' ###############################
' ##### QBasicToXBasic () #####
' ###############################
'
FUNCTION QBasicToXBasic (@qb$[], @xb$[])
'
DIM xb$[] ' no XBasic source
IFZ qb$[] THEN RETURN ' no QBasic source
'
Initialize () ' initialize everything
'
DIM #qbasic$[] '
DIM #xbasic$[] ' no XBasic source yet
SWAP #qbasic$[], qb$[] ' make QBasic source SHARED
'
ParseQBasic () ' convert #qbasic$[] source into tokens in #program[]
Translate () ' translate #program[] tokens into xbasic$[] source code
'
SWAP #qbasic$[], qb$[] ' restore QBasic source
SWAP #xbasic$[], xb$[] ' return XBasic source
END FUNCTION
'
'
' ############################
' ##### ParseQBasic () #####
' ############################
'
FUNCTION ParseQBasic ()
'
IFZ #qbasic$[] THEN RETURN ' no QBasic source program
#quline = UBOUND (#qbasic$[]) ' last line in QBasic source
'
' parse QBasic program into tokens-numbers in #program[function,line,token]
' creates symbol table in #token[] and #string$[]
'
line = 0
uline = 4095
DIM line[uline,]
'
#function = 0
'
FOR i = 0 TO #quline ' for all QBasic lines
DIM token[] ' start with zero tokens
function = #function ' remember this function-number
qbasic$ = #qbasic$[i] ' next line of QBasic source-code
qbasicline$ = qbasic$ '
ParseSourceLine (@qbasic$, @token[]) ' parse this line into tokens
IF #print THEN PRINT '
IF #print THEN PRINT qbasic$ '
IF #print THEN DeparseTokens (@token[], @line$) : PRINT line$
IF token[] THEN
IF (function != #function) THEN ' first executable line of new function
DEC line ' this line goes in the next function
REDIM line[line,] ' array size = number of lines in function
IF (#ufunction < #function) THEN
#ufunction = #ufunction + 1024 ' add 1024 lines to this function
REDIM #program[#ufunction,] ' make room for new lines of tokens in function
END IF
SWAP #program[#function,], line[] ' attach lines of tokens to program function
INC #function ' next function number
line = 0 ' first line in new function
uline = 4095 ' default number of lines in new function
DIM line[uline,] ' make room for lines of tokens in new function
END IF
END IF
IF (line > uline) THEN ' more lines than array space
uline = uline + 256 ' allow room for 256 more lines
REDIM line[uline,] ' make room for more lines of tokens
END IF
SWAP line[line,], token[] ' add tokens to program
NEXT i
END FUNCTION
'
'
' ##########################
' ##### Translate () #####
' ##########################
'
FUNCTION Translate ()
XLONG function[]
XLONG line[]
'
#xline = 0 ' start at beginning
DIM #xbasic$[] ' start with no XBasic
IFZ #program[] THEN RETURN ' no QBasic program tokens
XstLoadStringArray (@"start.txt", @start$[]) ' get standard XBasic startup
IFZ start$[] THEN RETURN ' support text-file missing
#xuline = #quline << 1 ' double room for XBasic
DIM xbasic$[#xuline] ' array to hold XBasic
OutputXBasic (@start$[]) ' startup #xbasic$[]
'
'
' translate QBasic tokens in #program[function,line,token] into XBasic source
'
line = 0
token = 0
#function = 0
#ufunction = UBOUND (#program[])
'
DIM func[]
DIM line[]
'
FOR function = 0 TO ufunction ' for all functions in program
SWAP #program[#function,], function[] ' function[] = tokens for function
uline = UBOUND (function[]) ' # of lines in this function
#function = function ' #function = this function
FOR line = 0 TO uline ' for all lines in function
SWAP function[line,], line[] ' line[] = tokens for next line
TranslateLine (@line[]) ' translate QBasic tokens to XBasic source
NEXT line '
NEXT function
END FUNCTION
'
'
' ##############################
' ##### TranslateLine () #####
' ##############################
'
FUNCTION TranslateLine (line[])
'
ntoken = 0
IFZ line[] THEN RETURN
utoken = UBOUND (line[])
'
' translate all statements on line
'
DO
done = TranslateStatement (@line[], @ntoken)
IF (ntoken > utoken) THEN EXIT DO
LOOP UNTIL done
END FUNCTION
'
'
' ###################################
' ##### TranslateStatement () #####
' ###################################
'
FUNCTION TranslateStatement (line[], ntoken)
END FUNCTION
'
'
' ##############################
' ##### DeparseTokens () #####
' ##############################
'
FUNCTION DeparseTokens (token[], line$)
'
line$ = ""
IFZ token[] THEN RETURN
'
upper = UBOUND (token[])
'
FOR i = 0 TO upper
token = token[i]
IFZ token THEN DO NEXT
whitestring = token >> 24
token = token AND 0x00FFFFFF
IF whitestring THEN line$ = line$ + #whitestring$[whitestring]
IF (token <= #utoken) THEN
line$ = line$ + #string$[#token[token].string]
END IF
NEXT i
END FUNCTION
'
'
' ################################
' ##### ParseSourceLine () ##### parse line of QBasic source into tokens
' ################################
'
FUNCTION ParseSourceLine (@line$, @line[])
STATIC FUNCADDR XLONG parseFunction[] (STRING, XLONG)
'
IFZ parseFunction[] THEN GOSUB LoadParseFunctionArray
'
offset = 0 ' offset to next character in line$
DIM line[] ' start with nothing on line
DIM #line[] ' start with no tokens on line
#whitebyte = 0 ' leading whitespace byte = zero
#nlinetoken = 0 ' where to put next token in #line[]
#ulinetoken = 255 ' upper bound of #line[] of tokens
DIM #line[#ulinetoken] ' make room for plenty of tokens
#functionLine = $$FALSE ' not function definition line
'
IFZ line$ THEN RETURN ' empty line
uchar = UBOUND (line$) ' uchar = upper character in line$
'
' parse the line - one language element at a time
'
DO ' all characters on line
char = line${offset} ' get next character on line
token = @parseFunction[char] (@line$, @offset) ' call appropriate function to process
token = token AND 0x00FFFFFF ' remove whitestring from token
IFZ token THEN EXIT DO ' zero token means end of line
'
IF (#ntoken == 1) THEN ' first important token on line
IF ((token == #Q_FUNCTION) OR (token == #Q_SUB)) THEN ' first line of new function
INC #function ' next function
END IF
END IF
LOOP WHILE (offset <= uchar)
'
IFZ #nlinetoken THEN ' nothing but whitespace = blank line
DIM #line[] '
DIM line[] '
ELSE '
REDIM #line[#nlinetoken] ' resize token array to minimum
#line[#nlinetoken] = 0 ' null terminate just in case
SWAP line[], #line[] ' return line[] of tokens
END IF '
'
RETURN ' end of function
'
'
'
' ****************************************
' ***** SUB LoadParseFunctionArray *****
' ****************************************
'
' Array parseFunction[] contains the addresses of the functions that
' should parse the next language-element, based on its 1st character.
' For example, if the first character of a language-element is "0"-"9",
' the language-element is some kind of number. "+","-",etc = operators.
' "A"-"Z", "a"-"z", "_" = some kind of symbol. space & tab = whitespace.
'
' ##### NOTE #####
'
' The following character ranges are more-or-less correct for XBasic,
' but almost certainly need a little modification for QBasic.
'
SUB LoadParseFunctionArray
DIM parseFunction[255]
FOR c = 0 TO 255
SELECT CASE TRUE
CASE (c >= 128) : parseFunction[c] = &ParseWhitespace() ' convert trash to spaces
CASE (c >= 123) : parseFunction[c] = &ParseCharacter() ' character or operator
CASE (c >= 97) : parseFunction[c] = &ParseSymbol() ' "a-z"
CASE (c == 95) : parseFunction[c] = &ParseSymbol() ' "_"
CASE (c >= 91) : parseFunction[c] = &ParseCharacter() ' character or operator
CASE (c >= 65) : parseFunction[c] = &ParseSymbol() ' "A-Z"
CASE (c >= 58) : parseFunction[c] = &ParseCharacter() ' character or operator
CASE (c >= 48) : parseFunction[c] = &ParseNumber() ' "0-9"
CASE (c == 36) : parseFunction[c] = &ParseSymbol() ' "$con" or "$$con
CASE (c == 35) : parseFunction[c] = &ParseSymbol() ' "#var" or "##var"
CASE (c >= 33) : parseFunction[c] = &ParseCharacter() ' character / operator
CASE (c == 32) : parseFunction[c] = &ParseWhitespace() ' space chars
CASE (c == 9) : parseFunction[c] = &ParseWhitespace() ' tab chars
CASE (c <= 8) : parseFunction[c] = &ParseWhitespace() ' convert trash to spaces
END SELECT
NEXT c
END SUB
END FUNCTION
'
'
' ################################
' ##### ParseWhitespace () ##### parse whitespace characters into a whitespace-string token
' ################################
'
' This function collects consecutive whitespace characters starting
' at offset in line$. This function then looks for the whitespace-string
' it collected in the 255 element #whitestring$[] array. If it finds an
' identical whitestring, it returns the element # of the matching element
' in #whitestring$[]. If it doesn't find a match, it adds the whitestring
' to #whitestring$[] and returns the element # of the new whitestring.
' If a program is wacko enough to have more than 255 different whitespace
' strings, this function will return one of the 255 existing whitespaces.
'
' The 255 whitespace values are designed to be imbedded in whatever token
' follows to indicate "leading whitespace".
'
FUNCTION ParseWhitespace (@line$, @offset)
'
token = 0
first = offset
#whitebyte = 0
'
DO
char = line${offset} ' char = next character
white = #charsetWhitespace[char] ' is character whitespace
IFZ char THEN RETURN #whitebyte ' clip trailing whitespace
IFZ white THEN EXIT DO ' exit unless whitespace
INC offset ' next character on line
LOOP
'
token = 0
past = offset
length = past - first
IFZ length THEN RETURN #whitebyte ' no whitespace
'
whitestring$ = MID$ (line$, first+1, length)
IFZ whitestring$ THEN RETURN #whitebyte
'
FOR i = 1 TO #nwhite
IF (whitestring$ == #whitestring$[i]) THEN #whitebyte = i : RETURN #whitebyte
NEXT i
'
' this whitestring is not yet in whitestring array, so add it
'
IF (#nwhite < #uwhite) THEN
INC #nwhite
#whitestring$[#nwhite] = whitestring$
#whitebyte = #nwhite
ELSE
#whitebyte = 1 ' no room for another whitestring, so fake one
END IF
'
RETURN #whitebyte
END FUNCTION
'
'
' ###############################
' ##### ParseCharacter () ##### parse special characters into the appropriate token
' ###############################
'
' This function parses 1 or more consecutive non-alphanumeric
' characters starting at offset in line$ into a symbol-token.
' Examples include operators ("<>", "<", "<=", "+", "*", "/")
' and other language elements ("[" "]" "(" ")" "'"), etc.
'
FUNCTION ParseCharacter (@line$, @offset)
STATIC SUBADDR parseCharacter[]
STATIC XLONG characterToken[]
'
IFZ characterToken[] THEN GOSUB Initialize
'
linelength = LEN (line$)
char = line${offset}
start = offset
INC offset
'
token = characterToken[char] ' this one character generates a token
IFZ token THEN GOSUB @parseCharacter[char] ' GOSUB a subroutine to parse this token
IF token THEN OutputToken (@token) ' add token to program
RETURN token
'
'
' characters that have their own tokens
'
SUB Character
symbol$ = CHR$ (char)
token = AddToken (0, 0, 0, $$KIND_CHARACTER, 0, 0, 0, 0, @symbol$)
IF token THEN #token[token].ivalue = char
END SUB
'
'
' *************************************************************************
' ***** Parse characters that may be part of 1+ character sequences *****
' *************************************************************************
'
'
'
' ***** & *****
'
' &O = prefix for octal literal : &O17777777777 = max-long : &O37777777777 = -1
' &H = prefix for hexadecimal literal
'
SUB Ampersand
value = 0 ' value = 0
digits = 0 ' hex digits
char = line${offset} ' char after &
'
INC offset ' offset to character after &O or &H prefix
'
SELECT CASE char
CASE 'O'
char = line${offset} ' but only if next character is 0-7
DO WHILE #charsetOctal[char] ' while character is 0-7
INC digits ' count valid hexadecimal digits
INC offset ' offset to next hexadecimal digit
SELECT CASE TRUE
CASE ((char >= '0') AND (char <= '7')) : octal = char - '0'
END SELECT
char = line${offset} ' next character
value = (value << 3) OR octal ' create cumulative hex value
LOOP UNTIL (value AND 0xE0000000) ' quit before 32-bits overflows
CASE 'H'
char = line${offset} ' but only if next character is 0-9 or A-F
DO WHILE #charsetHexUpper[char] ' while character is 0-9 or A-F
INC digits ' count valid hexadecimal digits
INC offset ' offset to next hexadecimal digit
SELECT CASE TRUE
CASE ((char >= '0') AND (char <= '9')) : hex = char - '0'
CASE ((char >= 'A') AND (char <= 'F')) : hex = char - 'A' + 10
' CASE ((char >= 'a') AND (char <= 'f')) : hex = char - 'a' + 10 ' always upper-case in QBasic
END SELECT
char = line${offset} ' next character
value = (value << 4) OR hex ' create cumulative hex value
LOOP UNTIL (value AND 0xF0000000) ' quit before 32-bits overflows
END SELECT
'
IFZ digits THEN
offset = start + 1
token = AddToken (0, 0, 0, $$KIND_CHARACTER, 0, 0, 0, 0, @"&")
ELSE
symbol$ = MID$ (line$, start+1, digits+2)
token = AddToken (0, 0, 0, $$KIND_LITERAL, $$TYPE_XLONG, 0, 0, 0, @symbol$)
IF token THEN #token[token].ivalue = value
END IF
END SUB
'
'
' ***** " ***** Literal string *****
'
SUB DoubleQuote
scans = offset ' 0 offset to character after opening double-quote
start = offset ' 1 offset to opening double-quote
final = linelength ' 0 offset to null-terminator
'
IF (scans < final) THEN
rawchar = line${scans}
DO UNTIL (rawchar = '"')
IF (rawchar = '\\') THEN
INC scans
rawchar = line${scans}
END IF
INC scans
rawchar = line${scans}
LOOP WHILE (scans < final)
END IF
'
IF (scans < final) THEN
INC scans
offset = scans ' terminated by " character - normal case
ELSE
offset = scans ' terminated by end-of-line null-terminator, not "
INC scans
END IF
'
lit$ = MID$ (line$, start, (scans-start)) + "\""
token = AddToken (0, 0, 0, $$KIND_LITERAL, $$TYPE_STRING, 0, 0, 0, @lit$)
END SUB
'
'
' ***** ' *****
'
SUB SingleQuote
comment$ = MID$ (line$, offset)
token = AddToken (0, 0, 0, $$KIND_COMMENT, $$TYPE_STRING, 0, 0, 0, @comment$)
offset = linelength
END SUB
'
'
' ***** . ***** .2345e3 (a number) or .component of composite
'
SUB Dot
two = line${offset}
SELECT CASE TRUE
CASE #charsetNumeric[two] ' a number, like .234567
DEC offset
token = ParseNumber (@line$, @offset)
CASE #charsetUpperLower[two] ' composite element, like .ssn in variable.ssn
DEC offset
token = ParseSymbol (@line$, @offset)
CASE ELSE ' standalone . is a syntax error
token = AddToken (0, 0, 0, $$KIND_CHARACTER, $$TYPE_UBYTE, 0, 0, 0, ".")
IF token THEN #token[token].ivalue = '.'
token = #Q_DOT
END SELECT
END SUB
'
'
' ***** < ***** < <> <=
'
SUB LessThan
two = line${offset} ' char after <
SELECT CASE two
CASE '>' : token = #Q_NE : INC offset ' <>
CASE '=' : token = #Q_LE : INC offset ' <=
CASE ELSE : token = #Q_LT ' <
END SELECT
END SUB
'
'
' ***** > ***** > >=
'
SUB GreaterThan
two = line${offset}
SELECT CASE two
CASE '=' : token = #Q_GE : INC offset ' >=
CASE ELSE : token = #Q_GT ' >
END SELECT
END SUB
'
'
'
' **********************************************************************************
' ***** load characterToken[] with tokens for 1-character length tokens only *****
' ***** load parseCharacter[] with addresses of routines to parse characters *****
' **********************************************************************************
'
SUB Initialize
DIM characterToken[255]
DIM parseCharacter[255]
'
' The following single characters get parsed into a token.
' In other words, whenever the first character a parse routine
' encounters is one of these characters, the single character
' always gets parsed into a token.
'
characterToken [ '+' ] = #Q_PLUS
characterToken [ '-' ] = #Q_MINUS
characterToken [ '*' ] = #Q_MULTIPLY
characterToken [ '/' ] = #Q_DIVIDE
characterToken [ '^' ] = #Q_POWER
characterToken [ '=' ] = #Q_EQ
' characterToken [ '&' ] = #Q_AMPERSAND ' does QuickBasic support & operator ???
characterToken ['\\' ] = #Q_IDIVIDE
characterToken [ '(' ] = #Q_LPAREN
characterToken [ ')' ] = #Q_RPAREN
characterToken [ '[' ] = #Q_LBRAK
characterToken [ ']' ] = #Q_RBRAK
characterToken [ ':' ] = #Q_COLON
characterToken [ ';' ] = #Q_SEMI
characterToken [ ',' ] = #Q_COMMA
'
' subroutines to process tokens starting with any character
'
' ' 00-32 handled elsewhere
parseCharacter [ '!' ] = SUBADDRESS (Character) ' !
parseCharacter [ '"' ] = SUBADDRESS (DoubleQuote) ' "
parseCharacter [ '#' ] = SUBADDRESS (Character) ' #
parseCharacter [ '$' ] = SUBADDRESS (Character) ' $
parseCharacter [ '%' ] = SUBADDRESS (Character) ' %
parseCharacter [ '&' ] = SUBADDRESS (Ampersand) ' &
parseCharacter [ ''' ] = SUBADDRESS (SingleQuote) ' '
parseCharacter [ '.' ] = SUBADDRESS (Dot) ' .
' ' 48-57 handled elsewhere
parseCharacter [ '<' ] = SUBADDRESS (LessThan) ' < <= <>
parseCharacter [ '>' ] = SUBADDRESS (GreaterThan) ' > >=
parseCharacter [ '?' ] = SUBADDRESS (Character) ' ?
parseCharacter [ '@' ] = SUBADDRESS (Character) ' @
' ' 65-90 handled elsewhere
parseCharacter [ '_' ] = SUBADDRESS (Character) ' _
parseCharacter [ '`' ] = SUBADDRESS (Character) ' `
' ' 97-122 handled elsewhere
parseCharacter [ '{' ] = SUBADDRESS (Character) ' {
parseCharacter [ '|' ] = SUBADDRESS (Character) ' |
parseCharacter [ '}' ] = SUBADDRESS (Character) ' }
parseCharacter [ '~' ] = SUBADDRESS (Character) ' ~
parseCharacter [ 127 ] = SUBADDRESS (Character) ' CHR$(127)
' ' 128-255 are white trash
END SUB
END FUNCTION
'
'
' ############################
' ##### ParseNumber () ##### parse a number into the appropriate number token
' ############################
'
FUNCTION ParseNumber (@line$, @offset)
'
enter = offset
start = offset
specType = XstStringToNumber (@line$, @start, @offset, @rtype, @value$$)
vhi = GHIGH (value$$)
vlo = GLOW (value$$)
value = vlo
'
suffix = line${offset}
IF (specType < 0) THEN specType = 0
'
' see if number is followed by a type-suffix
'
IFZ specType THEN
SELECT CASE suffix
CASE '%' : specType = $$TYPE_SSHORT : INC offset
CASE '&' : specType = $$TYPE_SLONG : INC offset
CASE '!' : specType = $$TYPE_SINGLE : INC offset
CASE '#' : specType = $$TYPE_DOUBLE : INC offset
END SELECT
END IF
'
number$ = MID$ (line$, start+1, offset-start)
'
' if type not specified by anything yet, decide on basis of the value
'
IFZ specType THEN
SELECT CASE rtype
CASE 0 : specType = $$SLONG ' zero
CASE $$TYPE_XLONG : specType = $$SLONG ' "0x..."
CASE $$TYPE_SINGLE : specType = $$SINGLE ' "0s..."
CASE $$TYPE_GIANT : specType = MinTypeFromGiant (value$$)
CASE $$TYPE_DOUBLE : value# = DMAKE (vhi, vlo)
specType = MinTypeFromDouble (value#)
CASE ELSE : PRINT "ParseNumber() : error" : RETURN ($$FALSE)
END SELECT
END IF
'
' add the literal number token to the token stream
'
type = specType
kind = $$KIND_LITERAL
token = AddToken (0, 0, 0, kind, type, 0, 0, 0, @number$)
IF token THEN
IF (type < $$TYPE_SINGLE) THEN #token[token].ivalue = value$$ ELSE #token[token].fvalue = value#
END IF
OutputToken (@token)
RETURN (token)
END FUNCTION
'
'
' ############################
' ##### ParseSymbol () ##### parse a symbol into the appropriate token
' ############################
'
FUNCTION ParseSymbol (@line$, @offset)
'
' collect the symbol
'
token = 0
start = offset
GetSymbol (@line$, @offset, @symbol$)
IFZ symbol$ THEN RETURN token
'
' is symbol a keyword or component of composite
'
firstchar = line${start}
afterchar = line${offset}
finalchar = line${offset-1}
'
' ??? keyword symbol ???
'
IF (firstchar != '.') THEN
token = TestForKeyword (@symbol$)
IF token THEN
OutputToken (token)
RETURN (token)
END IF
END IF
'
' 1st and 2nd tokens on line need special attention
'
SELECT CASE #tokenptr
CASE 0 : IF ((afterchar == ':') AND (LEN(symbol$) == offset)) THEN ' label:
INC offset
token = AddToken (0, 0, 0, $$KIND_LABEL, $$TYPE_GOADDR, 0, 0, 0, @symbol$)
OutputToken (@token)
RETURN (token)
END IF
CASE 1 : IF (#lasttoken == #Q_TYPE) THEN
IF #charsetUpperLower[firstchar] THEN
IF #charsetUpperLowerNumeric[finalchar] THEN
token = AddToken (0, 0, 0, $$KIND_TYPE, 0, 0, 0, 0, @symbol$)
OutputToken (@token)
RETURN (token)
END IF
END IF
END IF
END SELECT
'
' certain symbols are interpreted differently if following certain tokens
'
SELECT CASE #lasttoken
CASE #Q_GOTO ' GOTO label
token = AddToken (0, 0, 0, $$KIND_LABEL, $$TYPE_GOADDR, 0, 0, 0, @symbol$)
OutputToken (@token)
RETURN (token)
CASE #Q_GOSUB, #Q_SUB ' SUB subname or GOSUB subname
token = AddToken (0, 0, 0, $$KIND_LABEL, $$TYPE_SUBADDR, 0, 0, 0, @symbol$)
OutputToken (@token)
RETURN (token)
CASE #Q_LPAREN
SELECT CASE #backtoken
CASE T_GOADDRESS ' GOADDRESS (label)
token = AddToken (0, 0, 0, $$KIND_LABEL, $$TYPE_GOADDR, 0, 0, 0, @symbol$)
OutputToken (@token)
RETURN (token)
CASE T_SUBADDRESS ' SUBADDRESS (subname)
token = AddToken (0, 0, 0, $$KIND_LABEL, $$TYPE_SUBADDR, 0, 0, 0, @symbol$)
OutputToken (@token)
RETURN (token)
END SELECT
CASE ELSE
END SELECT
'
' symbols that begin with certain characters require special attention
'
' .components of composites
'
IF (firstchar = '.') THEN ' .COMPONENT name
token = AddToken (0, 0, 0, $$KIND_SYMBOL, 0, 0, 0, 0, @symbol$)
OutputToken (@token)
RETURN (token)
END IF
'
' normal symbols can have type suffix characters
'
SELECT CASE afterchar
CASE '@' : symbol$ = symbol$ + "@"
type = $$SBYTE
INC offset
CASE '%' : symbol$ = symbol$ + "%"
type = $$SSHORT
INC offset
CASE '&' : symbol$ = symbol$ + "&"
type = $$SLONG
INC offset
CASE '!' : symbol$ = symbol$ + "!"
type = $$SINGLE
INC offset
CASE '#' : symbol$ = symbol$ + "#"
type = $$DOUBLE
INC offset
CASE '$' : symbol$ = symbol$ + "$"
type = $$STRING
INC offset
CASE ELSE : type = 0
END SELECT
'
' see what follows trailing spaces/tabs
'
sx = 0
test = line${offset + sx}
DO WHILE (#charsetSpaceTab[test])
INC sx
test = line${offset + sx}
LOOP
'
' see if this is an array or function symbol
'
SELECT CASE test
CASE '(' : kind = $$KIND_FUNCTION
CASE '[' : kind = $$KIND_ARRAY
CASE ELSE : kind = $$KIND_VARIABLE
END SELECT
'
token = AddToken (0, 0, 0, kind, type, scope, 0, 0, @symbol$)
OutputToken (@token)
RETURN (token)
END FUNCTION
'
'
' ##########################
' ##### GetSymbol () #####
' ##########################
'
FUNCTION GetSymbol (line$, offset, symbol$)
'
start = offset
char = line${offset}
IF (char == '.') THEN INC offset : char = line${offset} ' .component symbol
'
DO WHILE (#charsetSymbolInner[char]) ' TRUE while A-Z, a-z, 0-9, "_"
INC offset
char = line${offset}
LOOP
'
symbol$ = MID$ (line$, start+1, offset-start)
END FUNCTION
'
'
' ############################
' ##### OutputToken () ##### parse a symbol into the appropriate token
' ############################
'
FUNCTION OutputToken (token)
'
#backtoken = #lasttoken
#lasttoken = token
'
IF (#nlinetoken > #ulinetoken) THEN
#ulinetoken = #ulinetoken + 256
REDIM #line[#ulinetoken]
END IF
'
IF (#whitebyte > 255) THEN #whitebyte = 1 ' disaster catcher
token = (#whitebyte << 24) + token ' put whitebyte in token
#line[#nlinetoken] = token ' add complete token to line of tokens
INC #nlinetoken ' next token in this line of tokens
#whitebyte = 0 ' whitestring output so cancel it
'
IF #print THEN PRINT " "; HEX$(token,8);
END FUNCTION
'
'
' ###############################
' ##### TestForKeyword () #####
' ###############################
'
FUNCTION TestForKeyword (string$)
'
token = 0
IFZ string$ THEN RETURN token
'
firstchar = string${0}
IF (firstchar = '_') THEN RETURN token
'
length = LEN (string$)
upper = length - 1
hash = 0
'
FOR i = 0 TO upper ' for all bytes in string
hash = hash + #hx[string${i}] ' add hash for that byte
NEXT i ' next byte in string
'
hash = hash AND 0x000000FF ' clip hash to byte
token = 0
'
' is symbol a QBasic keyword ???
'
FOR t = #qatoken TO #qztoken
IF (hash == #token[t].hash) THEN
IF (#string$[#token[t].string] == string$) THEN ' found keyword
token = t
EXIT FOR
END IF
END IF
NEXT t
RETURN token
END FUNCTION
'
'
' #################################
' ##### MinTypeFromGiant () #####
' #################################
'
FUNCTION MinTypeFromGiant (v$$)
'
SELECT CASE TRUE
CASE ((v$$ >= $$MIN_USHORT) AND (v$$ <= $$MAX_USHORT)) : rt = $$USHORT
CASE ((v$$ >= $$MIN_SSHORT) AND (v$$ <= $$MAX_SSHORT)) : rt = $$SSHORT
CASE ((v$$ >= $$MIN_SLONG) AND (v$$ <= $$MAX_SLONG)) : rt = $$SLONG
CASE ELSE : rt = $$GIANT
END SELECT
RETURN (rt)
END FUNCTION
'
'
' ##################################
' ##### MinTypeFromDouble () #####
' ##################################
'
FUNCTION MinTypeFromDouble (value#)
'
IF (value# < 0) THEN value# = -value#
minSingleExponent# = 0s00800000
maxSingleExponent# = 0s7F000000
IF (value# < minSingleExponent#) THEN RETURN ($$TYPE_DOUBLE)
IF (value# > maxSingleExponent#) THEN RETURN ($$TYPE_DOUBLE)
svalue! = value#
dvalue# = svalue!
IF (value# == dvalue#) THEN RETURN ($$TYPE_SINGLE)
RETURN ($$TYPE_DOUBLE)
END FUNCTION
'
'
' ###########################
' ##### AddKeyword () #####
' ###########################
'
FUNCTION AddKeyword (translate, function, scope, kind, type, atype1, atype2, atype3, string$)
'
ntoken = 0 ' 0 means failure
IFZ string$ THEN RETURN ntoken ' empty string is no keyword
'
IF (kind AND $$KIND_QBASIC) THEN qbasic = $$TRUE ELSE qbasic = $$FALSE
IF (kind AND $$KIND_XBASIC) THEN xbasic = $$TRUE ELSE xbasic = $$FALSE
'
length = LEN (string$) ' length of string
upper = length - 1 ' upper bound
hash = 0 ' initialize
'
FOR i = 0 TO upper ' for all bytes in string
hash = hash + #hx[string${i}] ' add hash for that byte
NEXT i ' next byte in string
'
hash = hash AND 0x000000FF ' clip hash to byte
hashtoken = #hash[hash] ' see if any tokens with this hash exist yet
INC #nstring ' store string in next string-number
INC #ntoken ' store token in next token-number
'
SELECT CASE #pass
CASE 1 : GOSUB PassOne ' establish token and string
CASE 2 : GOSUB PassTwo ' add translate token and string
END SELECT
RETURN ntoken '
'
'
' *********************
' ***** PassOne ***** update hash-links in tokens
' *********************
'
SUB PassOne
IFZ hashtoken THEN ' first string with this hash value
#hash[hash] = #ntoken ' remember first token with this hash
hashback = #ntoken ' this is also the last string with this hash
hashnext = 0 ' no more strings with this hash value yet
ELSE '
last = #token[hashtoken].hashback ' last contains last entry with this hash
next = #token[hashtoken].hashnext ' next contains second entry with this hash
IF #token[last].hashnext THEN STOP ' error if last token already points forward
#token[hashtoken].hashback = #ntoken ' point first token with this hash at this one
#token[last].hashnext = #ntoken ' last token with this hash becomes next-to-last
hashback = last ' previous token with this hash value
hashnext = 0 ' last token with this hash value
END IF
'
' add token information and symbol string
'
#string$[#nstring] = string$ ' add new symbol to string table
'
#token[#ntoken].translate = translate ' token in other language - QBasic or XBasic
#token[#ntoken].function = function ' function this token is defined in
#token[#ntoken].string = #nstring ' string that contains this symbol
#token[#ntoken].length = length ' length of this token symbol
#token[#ntoken].token = #ntoken ' token number of this token
#token[#ntoken].scope = scope ' scope of token
#token[#ntoken].kind = kind ' kind of token
#token[#ntoken].type = type ' type of token
#token[#ntoken].hash = hash ' hash of token
#token[#ntoken].hashback = hashback ' previous token with this hash
#token[#ntoken].hashnext = hashnext ' next token with this hash
#token[#ntoken].akind[0] = 0 ' kind of argument 0
#token[#ntoken].akind[1] = 0 ' kind of argument 1
#token[#ntoken].akind[2] = 0 ' kind of argument 2
#token[#ntoken].atype[0] = atype1 ' type of argument 0
#token[#ntoken].atype[1] = atype2 ' type of argument 1
#token[#ntoken].atype[2] = atype3 ' type of argument 2
#token[#ntoken].first = 0 '
#token[#ntoken].final = 0 '
#token[#ntoken].ivalue = 0$$ '
#token[#ntoken].fvalue = 0.00# '
ntoken = #ntoken
END SUB
'
'
' *********************
' ***** PassTwo ***** update hash-links in tokens
' *********************
'
SUB PassTwo
IF (#string$[#token[#ntoken].string] != string$) THEN PRINT "##### disaster #####" : EXIT SUB
IF (#token[#ntoken].function != function) THEN PRINT "##### disaster #####" : EXIT SUB
IF (#token[#ntoken].length != length) THEN PRINT "##### disaster #####" : EXIT SUB
IF (#token[#ntoken].token != #ntoken) THEN PRINT "##### disaster #####" : EXIT SUB
IF (#token[#ntoken].scope != scope) THEN PRINT "##### disaster #####" : EXIT SUB
IF (#token[#ntoken].kind != kind) THEN PRINT "##### disaster #####" : EXIT SUB
IF (#token[#ntoken].type != type) THEN PRINT "##### disaster #####" : EXIT SUB
'
#token[#ntoken].translate = translate
ntoken = #ntoken
END SUB
END FUNCTION
'
'
' ##########################
' ##### FindToken () #####
' ##########################
'
FUNCTION FindToken (@match[], function, scope, kind, type, atype1, atype2, atype3, string$)
'
ntoken = 0 ' token not found
DIM match[] ' no matches found yet
IFZ string$ THEN RETURN ntoken ' empty symbol is no symbol
'
IF (kind AND $$KIND_QBASIC) THEN qbasic = $$TRUE ELSE qbasic = $$FALSE
IF (kind AND $$KIND_XBASIC) THEN xbasic = $$TRUE ELSE xbasic = $$FALSE
'
length = LEN (string$) ' length of string in bytes
upper = length - 1 ' upper bound of string
hash = 0 ' initialize hash
'
FOR i = 0 TO upper ' for all bytes in string
hash = hash + #hx[string${i}] ' add hash for that byte
NEXT i
'
hash = hash AND 0x000000FF ' clip hash to byte value
'
ntoken = #hash[hash] ' first entry with this hash
IFZ ntoken THEN RETURN $$FALSE ' no symbol with this hash
'
' check all symbols with this hash for a match
'
'
nmatch = 0 ' number of matches
umatch = 15 ' maximum match number
DIM match[umatch] ' upper bound of match[]
'
DO
symbol = #token[ntoken].string ' entry in string table
IF (symbol$ == #string$[string]) THEN ' symbols match
IF (function == #token[ntoken].function) THEN ' functions match
IF (nmatch > umatch) THEN ' make more room
umatch = umatch + 16 ' 16 more now
REDIM match[umatch] ' make room
END IF '
match[nmatch] = ntoken ' return the token
INC nmatch ' next match number
END IF '
END IF
ntoken = #token[ntoken].hashnext ' next token with same hash
LOOP WHILE ntoken ' no more tokens with this hash
END FUNCTION
'
'
' #########################
' ##### AddToken () #####
' #########################
'
FUNCTION AddToken (@token, function, scope, kind, type, atype1, atype2, atype3, string$)
'
ntoken = 0 ' token not added
IFZ string$ THEN RETURN ntoken ' empty string is no symbol
'
IF (kind AND $$KIND_QBASIC) THEN qbasic = $$TRUE ELSE qbasic = $$FALSE
IF (kind AND $$KIND_XBASIC) THEN xbasic = $$TRUE ELSE xbasic = $$FALSE
'
length = LEN (string$) ' length of string in bytes
upper = length - 1 ' upper bound of string
hash = 0 ' initialize hash
'
FOR i = 0 TO upper ' for all bytes in string
hash = hash + #hx[string${i}] ' add hash for that byte
NEXT i ' next byte in string
'
hash = hash AND 0x000000FF ' clip hash to byte
hashtoken = #hash[hash] ' see if any tokens with this hash exist yet
ntoken = 0 ' no token yet
'
' If no token has this hash, this must be a new token, and
' therefore this token is definitely added to symbol-table.
'
IFZ hashtoken THEN GOSUB NewHash
IF ntoken THEN RETURN ntoken
'
' If token already exists, return the existing token
'
GOSUB FindToken
IF ntoken THEN RETURN ntoken
'
' otherwise create and return a new token
'
GOSUB AddToken
RETURN ntoken
'
'
' *********************
' ***** NewHash ***** token must be new because hash-value is zero
' *********************
'
SUB NewHash
ntoken = 0
INC #ntoken ' store token in next token-number
INC #nstring ' store string in next string-number
#hash[hash] = #ntoken ' remember base-token with this hash
#token[#ntoken].hashback = #ntoken ' this is also the last string with this hash
#token[#ntoken].hashnext = #ntoken ' this is also the next string with this hash
'
#token[#ntoken].hash = hash '
#token[#ntoken].kind = kind '
#token[#ntoken].type = type '
#token[#ntoken].scope = scope '
#token[#ntoken].token = #ntoken '
#token[#ntoken].length = length '
#token[#ntoken].string = #nstring '
#token[#ntoken].function = function '
#token[#ntoken].atype[1] = atype1 '
#token[#ntoken].atype[2] = atype2 '
#token[#ntoken].atype[3] = atype3 '
#string$[#nstring] = string$ '
ntoken = #ntoken ' return token number of this new token
token = ntoken
END SUB
'
'
' ***********************
' ***** FindToken *****
' ***********************
'
SUB FindToken
ntoken = 0
last = #token[hashtoken].hashback ' last contains last entry with this hash
next = #token[hashtoken].hashnext ' next contains second entry with this hash
token = last ' start with last token with this hash value
'
DO
IF (kind == #token[token].kind) THEN
IF (hash == #token[token].hash) THEN
IF (scope == #token[token].scope) THEN
IF (length == #token[token].length) THEN
IF (string$ == #string$[#token[token].string]) THEN ' found token
ntoken = token
EXIT DO
END IF
END IF
END IF
END IF
END IF
IF (token == hashtoken) THEN EXIT DO ' no more tokens with this hash value
token = #token[token].hashback ' next token to test
LOOP
END SUB
'
'
' **********************
' ***** AddToken *****
' **********************
'
SUB AddToken
ntoken = 0 ' new token not added yet
INC #ntoken ' store token in next token-number
INC #nstring ' store string in next string-number
last = #token[hashtoken].hashback ' last contains last entry with this hash
'
#token[#ntoken].hashback = last ' new last-entry points back to old last-entry
#token[#ntoken].hashnext = hashtoken ' new last-entry points back at first-entry
#token[last].hashnext = #ntoken ' old last-entry points next to new last-entry
#token[hashtoken].hashback = #ntoken ' the base-entry points back at new last-entry
'
#hash[hash] = #ntoken ' remember first token with this hash
#token[#ntoken].hash = hash '
#token[#ntoken].kind = kind '
#token[#ntoken].type = type '
#token[#ntoken].scope = scope '
#token[#ntoken].token = #ntoken '
#token[#ntoken].length = length '
#token[#ntoken].string = #nstring '
#token[#ntoken].function = function '
#token[#ntoken].atype[1] = atype1 '
#token[#ntoken].atype[2] = atype2 '
#token[#ntoken].atype[3] = atype3 '
#string$[#nstring] = string$ '
ntoken = #ntoken ' return token number of this new token
token = ntoken
END SUB
END FUNCTION
'
'
' #############################
' ##### OutputXBasic () #####
' #############################
'
FUNCTION OutputXBasic (text$[])
IFZ text$[] THEN RETURN
upper = UBOUND (text$[])
lines = upper + 1
'
new = #xline + lines
'
IF (new > (#xuline - 256)) THEN
#xuline = #xuline + 1024
REDIM #xbasic$[#xuline]
END IF
'
FOR i = 0 TO upper
#xbasic$[#xline] = text$[i]
INC #xline
NEXT i
END FUNCTION
'
'
' ################################
' ##### TokenRestOfLine () #####
' ################################
'
FUNCTION TokenRestOfLine ()
'
' xxxxx
'
END FUNCTION
'
'
' ############################
' ##### PrintTokens () #####
' ############################
'
FUNCTION PrintTokens ()
'
FOR i = 0 TO #ntoken+1
IFZ (i AND 0x000F) THEN PRINT " tok# trantok# hash back next func kind datatype scope integer-value length symbol-string translate-symbol"
PRINT " ";
PRINT HEX$(#token[i].token,4);;
PRINT HEX$(#token[i].translate,8);;
PRINT HEX$(#token[i].hash,4);;
PRINT HEX$(#token[i].hashback,4);;
PRINT HEX$(#token[i].hashnext,4);;
PRINT HEX$(#token[i].function,4);;
PRINT HEX$(#token[i].kind,8);;
PRINT HEX$(#token[i].type,8);;
PRINT HEX$(#token[i].scope,5);;
PRINT HEX$(#token[i].ivalue,16);;
' PRINT HEX$(#token[i].fvalue,16);;
PRINT HEX$(#token[i].length,6);;;
PRINT FORMAT$("<<<<<<<<<<<<<<<<", #string$[#token[i].string]);;
'
translate = #token[i].translate
IF translate THEN PRINT #string$[#token[translate].string] ELSE PRINT
NEXT i
END FUNCTION
'
'
' ##########################
' ##### PrintHash () #####
' ##########################
'
FUNCTION PrintHash ()
'
FOR i = 0 TO 255
PRINT HEX$(i,2); " : ";
n = #hash[i]
DO WHILE n
PRINT HEX$(n,4);;
n = #token[n].hashnext
LOOP
PRINT
NEXT i
END FUNCTION
'
'
' ##########################
' ##### Terminate () #####
' ##########################
'
FUNCTION Terminate ()
'
' xxxxx
'
END FUNCTION
END PROGRAM