'All variables will be of type LONG unless explicitly defined
DEFLNG A-Z

'All arrays will be dynamically allocated so they can be REDIM-ed
'$DYNAMIC

'We need console access to support command-line compilation via the -x command line compile option
$CONSOLE

'Initially the "SCREEN" will be hidden, if the -x option is used it will never be created
$SCREENHIDE

$EXEICON:'./qb64pe.ico'

$VERSIONINFO:CompanyName='QB64 Phoenix Edition'
$VERSIONINFO:FileDescription='QB64 IDE and Compiler'
$VERSIONINFO:InternalName='qb64pe.bas'
$VERSIONINFO:LegalCopyright='MIT'
$VERSIONINFO:LegalTrademarks=''
$VERSIONINFO:OriginalFilename='qb64pe.exe'
$VERSIONINFO:ProductName='QB64-PE'
$VERSIONINFO:Comments='QB64 is a modern extended BASIC programming language that retains QB4.5/QBasic compatibility and compiles native binaries for Windows, Linux and macOS.'

'$INCLUDE:'global\version.bas'
'$INCLUDE:'global\settings.bas'
'$INCLUDE:'global\constants.bas'
'$INCLUDE:'subs_functions\extensions\opengl\opengl_global.bas'
'$INCLUDE:'utilities\ini-manager\ini.bi'
'$INCLUDE:'utilities\s-buffer\simplebuffer.bi'
'$INCLUDE:'utilities\const_eval.bi'
'$INCLUDE:'utilities\give_error.bi'
'$INCLUDE:'utilities\statevars.bi'
'$INCLUDE:'utilities\type.bi'

DEFLNG A-Z

'-------- Optional IDE Component (1/2) --------
'$INCLUDE:'ide\ide_global.bas'

DIM SHARED NoExeSaved AS _BYTE

DIM SHARED vWatchErrorCall$, vWatchNewVariable$, vWatchVariableExclusions$
vWatchErrorCall$ = "if (stop_program) {*__LONG_VWATCH_LINENUMBER=0; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars);};if(new_error){bkp_new_error=new_error;new_error=0;*__LONG_VWATCH_LINENUMBER=-1; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars);new_error=bkp_new_error;};"
vWatchVariableExclusions$ = "@__LONG_VWATCH_LINENUMBER@__LONG_VWATCH_SUBLEVEL@__LONG_VWATCH_GOTO@" + _
              "@__STRING_VWATCH_SUBNAME@__STRING_VWATCH_CALLSTACK@__ARRAY_BYTE_VWATCH_BREAKPOINTS" + _
              "@__ARRAY_BYTE_VWATCH_SKIPLINES@__STRING_VWATCH_INTERNALSUBNAME@__ARRAY_STRING_VWATCH_STACK@"

DIM SHARED nativeDataTypes$
nativeDataTypes$ = "@_OFFSET@_UNSIGNED _OFFSET@_BIT@_UNSIGNED _BIT@_BYTE@_UNSIGNED _BYTE@INTEGER@_UNSIGNED INTEGER@LONG@_UNSIGNED LONG@_INTEGER64@_UNSIGNED _INTEGER64@SINGLE@DOUBLE@_FLOAT@STRING@"

REDIM EveryCaseSet(100), SelectCaseCounter AS _UNSIGNED LONG
REDIM SelectCaseHasCaseBlock(100)
DIM ExecLevel(255), ExecCounter AS INTEGER
REDIM SHARED UserDefine(1, 100) AS STRING '0 element is the name, 1 element is the string value
REDIM SHARED InvalidLine(10000) AS _BYTE 'True for lines to be excluded due to preprocessor commands
DIM DefineElse(255) AS _BYTE
DIM SHARED UserDefineCount AS INTEGER, UserDefineCountPresets AS INTEGER, UserDefineList$, UserDefineListPresets$
UserDefineListPresets$ = "@DEFINED@UNDEFINED@WINDOWS@WIN@LINUX@MAC@MACOSX@32BIT@64BIT@VERSION@_QB64PE_@_ARM_@"
UserDefine(0, 0) = "WINDOWS": UserDefine(0, 1) = "WIN"
UserDefine(0, 2) = "LINUX"
UserDefine(0, 3) = "MAC": UserDefine(0, 4) = "MACOSX"
UserDefine(0, 5) = "32BIT": UserDefine(0, 6) = "64BIT"
UserDefine(0, 7) = "VERSION": UserDefine(0, 8) = "_QB64PE_"
UserDefine(0, 9) = "_ARM_"
IF INSTR(_OS$, "WIN") THEN UserDefine(1, 0) = "-1": UserDefine(1, 1) = "-1" ELSE UserDefine(1, 0) = "0": UserDefine(1, 1) = "0"
IF INSTR(_OS$, "LINUX") THEN UserDefine(1, 2) = "-1" ELSE UserDefine(1, 2) = "0"
IF INSTR(_OS$, "MAC") THEN UserDefine(1, 3) = "-1": UserDefine(1, 4) = "-1" ELSE UserDefine(1, 3) = "0": UserDefine(1, 4) = "0"
IF INSTR(_OS$, "32BIT") THEN UserDefine(1, 5) = "-1": UserDefine(1, 6) = "0" ELSE UserDefine(1, 5) = "0": UserDefine(1, 6) = "-1"
UserDefine(1, 7) = Version$: UserDefine(1, 8) = "-1"
IF INSTR(_OS$, "ARM") THEN UserDefine(1, 9) = "-1" ELSE UserDefine(1, 9) = "0"
'Whatever values get added/changed in the future, make sure to keep
'the VERSION on index #7 to avoid problems.
UserDefineCountPresets = 9 'the last index of the defines above

DIM SHARED QB64_uptime#

QB64_uptime# = TIMER(0.001)

NoInternalFolder:
IF _DIREXISTS("internal") = 0 THEN
    _SCREENSHOW
    PRINT "QB64-PE cannot locate the 'internal' folder"
    PRINT
    PRINT "Check that QB64-PE has been extracted properly."
    PRINT "For MacOSX, launch 'qb64pe_start.command' or enter './qb64pe' in Terminal."
    PRINT "For Linux, in the console enter './qb64pe'."
    DO
        _LIMIT 1
    LOOP UNTIL INKEY$ <> ""
    SYSTEM 1
END IF

DIM SHARED DEPENDENCY_LAST
CONST DEPENDENCY_LOADFONT = 1: DEPENDENCY_LAST = DEPENDENCY_LAST + 1
CONST DEPENDENCY_MINIAUDIO = 2: DEPENDENCY_LAST = DEPENDENCY_LAST + 1
CONST DEPENDENCY_GL = 3: DEPENDENCY_LAST = DEPENDENCY_LAST + 1
CONST DEPENDENCY_IMAGE_CODEC = 4: DEPENDENCY_LAST = DEPENDENCY_LAST + 1
CONST DEPENDENCY_CONSOLE_ONLY = 5: DEPENDENCY_LAST = DEPENDENCY_LAST + 1
CONST DEPENDENCY_SOCKETS = 6: DEPENDENCY_LAST = DEPENDENCY_LAST + 1
CONST DEPENDENCY_PRINTER = 7: DEPENDENCY_LAST = DEPENDENCY_LAST + 1
CONST DEPENDENCY_ICON = 8: DEPENDENCY_LAST = DEPENDENCY_LAST + 1
CONST DEPENDENCY_SCREENIMAGE = 9: DEPENDENCY_LAST = DEPENDENCY_LAST + 1
CONST DEPENDENCY_DEVICEINPUT = 10: DEPENDENCY_LAST = DEPENDENCY_LAST + 1 'removes support for gamepad input if not present
CONST DEPENDENCY_ZLIB = 11: DEPENDENCY_LAST = DEPENDENCY_LAST + 1 'ZLIB library linkage, if desired, for compression/decompression.
CONST DEPENDENCY_EMBED = 12: DEPENDENCY_LAST = DEPENDENCY_LAST + 1 '$EMBED stuff, trigger make of internal\temp\embedded.cpp



DIM SHARED DEPENDENCY(1 TO DEPENDENCY_LAST)

DIM SHARED UseGL 'declared SUB _GL (no params)


DIM SHARED WindowTitle AS STRING

IF INSTR(_OS$, "ARM") THEN
    WindowTitle = "QB64 Phoenix Edition " + _IIF(OS_BITS = 32, "(ARM)", "(ARM64)")
ELSE
    WindowTitle = "QB64 Phoenix Edition " + _IIF(OS_BITS = 32, "(x86)", "(x64)")
END IF

_TITLE WindowTitle

CONST METACOMMAND_STRING_ENCLOSING_PAIR = "''"

DIM SHARED AS _BYTE NoIDEMode, ConsoleMode, FormatMode, NoCCompileMode, QuietMode
DIM SHARED AS _BYTE MonochromeLoggingMode, ShowWarnings, ForceOptExpl
DIM SHARED CMDLineSrcFile$, CMDLineOutFile$

TYPE usedVarList
    AS LONG id, linenumber, includeLevel, includedLine, scope, localIndex
    AS LONG arrayElementSize
    AS _BYTE used, watch, isarray, displayFormat 'displayFormat: 0=DEC;1=HEX;2=BIN;3=OCT
    AS STRING name, cname, varType, includedFile, subfunc
    AS STRING watchRange, indexes, elements, elementTypes 'for Arrays and UDTs
    AS STRING elementOffset, storage
END TYPE

REDIM SHARED backupUsedVariableList(1000) AS usedVarList
DIM SHARED typeDefinitions$, backupTypeDefinitions$
DIM SHARED totalVariablesCreated AS LONG, totalMainVariablesCreated AS LONG
DIM SHARED totalWarnings AS LONG, warningListItems AS LONG, lastWarningHeader AS STRING
DIM SHARED duplicateConstWarning AS _BYTE, warningsissued AS _BYTE
DIM SHARED emptySCWarning AS _BYTE, maxLineNumber AS LONG
DIM SHARED ExeIconSet AS LONG
DIM SHARED VersionInfoSet AS _BYTE

'Array to handle $EMBED metacommand:
REDIM SHARED embedFileList$(3, 10)
CONST eflLine = 0, eflUsed = 1, eflFile = 2, eflHand = 3 '1st index IDs

'Array to handle $USELIBRARY metacommand:
REDIM SHARED useLibList$(4, 10)
CONST ullName = 0, ullNeedy = 1, ullTop = 2, ullMain = 3, ullBottom = 4 '1st index IDs

'Variables to handle $VERSIONINFO metacommand:
DIM SHARED viFileVersionNum$, viProductVersionNum$, viCompanyName$
DIM SHARED viFileDescription$, viFileVersion$, viInternalName$
DIM SHARED viLegalCopyright$, viLegalTrademarks$, viOriginalFilename$
DIM SHARED viProductName$, viProductVersion$, viComments$, viWeb$

DIM SHARED ColorSet AS RCStateVar
DIM SHARED OptExpl AS RCStateVar
DIM SHARED OptExplArr AS RCStateVar
DIM SHARED AssertsOn AS RCStateVar
DIM SHARED ConsoleOn AS RCStateVar
DIM SHARED vWatchOn AS RCStateVar
DIM SHARED SockDepOn AS RCStateVar
DIM SHARED ErrorLocationMode AS RCStateVar
DIM SHARED CheckingOn
DIM SHARED ScreenHideOn
DIM SHARED ResizeOn, ResizeScale

DIM SHARED OptMax AS LONG
OptMax = 256
REDIM SHARED Opt(1 TO OptMax, 1 TO 10) AS STRING * 256
'   (1,1)="READ"
'   (1,2)="WRITE"
'   (1,3)="READ WRITE"
REDIM SHARED OptWords(1 TO OptMax, 1 TO 10) AS INTEGER 'The number of words of each opt () element
'   (1,1)=1 '"READ"
'   (1,2)=1 '"WRITE"
'   (1,3)=2 '"READ WRITE"
REDIM SHARED T(1 TO OptMax) AS INTEGER 'The type of the entry
'   t is 0 for ? opts
'   ---------- 0 means ? , 1+ means a symbol or {}block ----------
'   t is 1 for symbol opts
'   t is the number of rhs opt () index entries for {READ|WRITE|READ WRITE} like opts
REDIM SHARED Lev(1 TO OptMax) AS INTEGER 'The indwelling level of each opt () element (the lowest is 0)
REDIM SHARED EntryLev(1 TO OptMax) AS INTEGER 'The level required from which this opt () can be validly be entered/checked-for
REDIM SHARED DitchLev(1 TO OptMax) AS INTEGER 'The lowest level recorded between the previous Opt and this Opt
REDIM SHARED DontPass(1 TO OptMax) AS INTEGER 'Set to 1 or 0, with 1 meaning don't pass
'Determines whether the opt () entry needs to actually be passed to the C++ sub/function
REDIM SHARED TempList(1 TO OptMax) AS INTEGER
REDIM SHARED PassRule(1 TO OptMax) AS LONG
'0 means no pass rule
'negative values refer to an opt () element
'positive values refer to a flag value
REDIM SHARED LevelEntered(OptMax) 'up to 64 levels supported
REDIM SHARED separgs(OptMax + 1) AS STRING
REDIM SHARED separgslayout(OptMax + 1) AS STRING
REDIM SHARED separgs2(OptMax + 1) AS STRING
REDIM SHARED separgslayout2(OptMax + 1) AS STRING




'E is used with the 'qberror_test' handler. If the handler is called (i.e. when an error
'occures), then E is simply set to 1. Properly resetting E to 0 prior error testing is
'up to the code which uses the 'qberror_test' handler for checking.
DIM SHARED E

DIM member_element_id AS LONG 'metadata index of the currently resolved TYPE member array








DIM SHARED ResolveStaticFunctions
REDIM SHARED ResolveStaticFunction_File(1 TO 100) AS STRING
REDIM SHARED ResolveStaticFunction_Name(1 TO 100) AS STRING
REDIM SHARED ResolveStaticFunction_Method(1 TO 100) AS LONG





DIM SHARED os AS STRING
os$ = "WIN"
IF INSTR(_OS$, "[LINUX]") THEN os$ = "LNX"

DIM SHARED MacOSX AS LONG
IF INSTR(_OS$, "[MACOSX]") THEN MacOSX = 1


DIM SHARED BATCHFILE_EXTENSION AS STRING
BATCHFILE_EXTENSION = ".bat"
IF os$ = "LNX" THEN BATCHFILE_EXTENSION = ".sh"
IF MacOSX THEN BATCHFILE_EXTENSION = ".command"


DIM inlinedatastr(0 TO 255) AS STRING
FOR i = 0 TO 255
    inlinedatastr(i) = _TOSTR$(i) + ","
NEXT


DIM SHARED extension AS STRING
DIM SHARED path.exe$, path.source$, lastBinaryGenerated$
extension$ = ".exe"
IF os$ = "LNX" THEN extension$ = "" 'no extension under Linux

DIM SHARED pathsep AS STRING * 1
pathsep$ = "\"
IF os$ = "LNX" THEN pathsep$ = "/"
'note: QB64 handles OS specific path separators automatically except under SHELL calls

ON ERROR GOTO qberror_test

DIM SHARED tmpdir AS STRING, tmpdir2 AS STRING
IF os$ = "WIN" THEN tmpdir$ = ".\internal\temp\": tmpdir2$ = "..\\temp\\"
IF os$ = "LNX" THEN tmpdir$ = "./internal/temp/": tmpdir2$ = "../temp/"

IF NOT _DIREXISTS(tmpdir$) THEN MKDIR tmpdir$

DECLARE LIBRARY
    FUNCTION getpid& ()
END DECLARE

thisinstancepid = getpid&
DIM SHARED tempfolderindex

IF INSTR(_OS$, "LINUX") THEN
    fh = FREEFILE
    OPEN ".\internal\temp\tempfoldersearch.bin" FOR RANDOM AS #fh LEN = LEN(tempfolderindex)
    tempfolderrecords = LOF(fh) / LEN(tempfolderindex)
    i = 1
    IF tempfolderrecords = 0 THEN
        'first run ever?
        PUT #fh, 1, thisinstancepid
    ELSE
        FOR i = 1 TO tempfolderrecords
            'check if any of the temp folders is being used = pid still active
            GET #fh, i, tempfoldersearch

            SHELL _HIDE "ps -p " + STR$(tempfoldersearch) + " > /dev/null 2>&1; echo $? > internal/temp/checkpid.bin"
            fh2 = FREEFILE
            OPEN "internal/temp/checkpid.bin" FOR BINARY AS #fh2
            LINE INPUT #fh2, checkpid$
            CLOSE #fh2
            IF VAL(checkpid$) = 1 THEN
                'This temp folder was locked by an instance that's no longer active, so
                'this will be our temp folder
                PUT #fh, i, thisinstancepid
                EXIT FOR
            END IF
        NEXT
        IF i > tempfolderrecords THEN
            'All indexes were busy. Let's initiate a new one:
            PUT #fh, i, thisinstancepid
        END IF
    END IF
    CLOSE #fh
    IF i > 1 THEN
        tmpdir$ = "./internal/temp" + _TOSTR$(i) + "/": tmpdir2$ = "../temp" + _TOSTR$(i) + "/"
        IF _DIREXISTS(tmpdir$) = 0 THEN
            MKDIR tmpdir$
        END IF
    END IF
    OPEN tmpdir$ + "temp.bin" FOR OUTPUT LOCK WRITE AS #26
ELSE
    ON ERROR GOTO qberror_test
    E = 0
    i = 1
    OPEN tmpdir$ + "temp.bin" FOR OUTPUT LOCK WRITE AS #26
    DO WHILE E
        i = i + 1
        IF i = 1000 THEN PRINT "Unable to locate the 'internal' folder": END 1
        MKDIR ".\internal\temp" + _TOSTR$(i)
        IF os$ = "WIN" THEN tmpdir$ = ".\internal\temp" + _TOSTR$(i) + "\": tmpdir2$ = "..\\temp" + _TOSTR$(i) + "\\"
        IF os$ = "LNX" THEN tmpdir$ = "./internal/temp" + _TOSTR$(i) + "/": tmpdir2$ = "../temp" + _TOSTR$(i) + "/"
        E = 0
        OPEN tmpdir$ + "temp.bin" FOR OUTPUT LOCK WRITE AS #26
    LOOP
END IF


'temp folder established
tempfolderindex = i
IF i > 1 THEN
    'create modified version of qbx.cpp
    OPEN ".\internal\c\qbx" + _TOSTR$(i) + ".cpp" FOR OUTPUT AS #2
    OPEN ".\internal\c\qbx.cpp" FOR BINARY AS #1
    DO UNTIL EOF(1)
        LINE INPUT #1, a$
        x = INSTR(a$, "..\\temp\\"): IF x THEN a$ = LEFT$(a$, x - 1) + "..\\temp" + _TOSTR$(i) + "\\" + RIGHT$(a$, LEN(a$) - (x + 9))
        x = INSTR(a$, "../temp/"): IF x THEN a$ = LEFT$(a$, x - 1) + "../temp" + _TOSTR$(i) + "/" + RIGHT$(a$, LEN(a$) - (x + 7))
        PRINT #2, a$
    LOOP
    CLOSE #1, #2
END IF

IF Debug THEN OPEN tmpdir$ + "debug.txt" FOR OUTPUT AS #9

'look if the Libraries Pack add-on is available,
'and if so, find the Library Explorer executable
LibExplorer$ = ""
IF _DIREXISTS("libraries") _ORELSE _DIREXISTS("./libraries") THEN
    IF _FILEEXISTS("LibraryExplorer.exe") THEN LibExplorer$ = "LibraryExplorer.exe"
    IF _FILEEXISTS("./LibraryExplorer") THEN LibExplorer$ = "./LibraryExplorer"
    IF _FILEEXISTS("libraries\LibraryExplorer.exe") THEN LibExplorer$ = "libraries\LibraryExplorer.exe"
    IF _FILEEXISTS("./libraries/LibraryExplorer") THEN LibExplorer$ = "./libraries/LibraryExplorer"
END IF

ON ERROR GOTO qberror



DIM SHARED tempfolderindexstr AS STRING 'appended to "Untitled"
IF tempfolderindex <> 1 THEN tempfolderindexstr$ = "(" + _TOSTR$(tempfolderindex) + ")"


DIM SHARED seperateargs_error
DIM SHARED seperateargs_error_message AS STRING

DIM SHARED compfailed

DIM SHARED reginternalsubfunc
DIM SHARED reginternalvariable


DIM SHARED symboltype_size
symboltype_size = 0

DIM SHARED use_global_byte_elements
use_global_byte_elements = 0

'compiler-side IDE data & definitions
'SHARED variables "passed" to/from the compiler & IDE
DIM SHARED idecommand AS STRING 'a 1 byte message-type code, followed by optional string data
DIM SHARED idereturn AS STRING 'used to pass formatted-lines and return information back to the IDE
DIM SHARED ideerror AS LONG
DIM SHARED idecompiled AS LONG
DIM SHARED idemode '1 if using the IDE to compile
DIM SHARED ideerrorline AS LONG 'set by qb64-error(...) to the line number it would have reported, this number
'is later passed to the ide in message #8
DIM SHARED idemessage AS STRING 'set by qb64-error(...) to the error message to be reported, this
'is later passed to the ide in message #8

DIM SHARED IDEStartAtLine AS LONG, errorLineInInclude AS LONG
DIM SHARED warningInInclude AS LONG, warningInIncludeLine AS LONG
DIM SHARED compilelog$

'$INCLUDE:'ide\config\cfg_global.bas'
ReadInitialConfig

CMDLineSrcFile$ = ParseCMDLineArgs$
IF LEN(CMDLineSrcFile$) > 0 _ANDALSO _FILEEXISTS(_STARTDIR$ + CMDLineSrcFile$) THEN
    CMDLineSrcFile$ = _STARTDIR$ + CMDLineSrcFile$
END IF
IF LEN(CMDLineOutFile$) > 0 _ANDALSO _DIREXISTS(_STARTDIR$ + getfilepath$(CMDLineOutFile$)) THEN
    CMDLineOutFile$ = _STARTDIR$ + CMDLineOutFile$
END IF

IF ConsoleMode THEN
    _DEST _CONSOLE
ELSE
    _CONSOLE OFF
    _SCREENSHOW
    _ICON
END IF

'$INCLUDE:'utilities\hash.bi'

TYPE Label_Type
    State AS _UNSIGNED _BYTE '0=label referenced, 1=label created
    cn AS STRING * 256
    Scope AS LONG
    Data_Offset AS _INTEGER64 'offset within data
    Data_Referenced AS _UNSIGNED _BYTE 'set to 1 if data is referenced (data_offset will be used to create the data offset variable)
    Error_Line AS LONG 'the line number to reference on errors
    Scope_Restriction AS LONG 'cannot exist inside this scope (post checked)
    SourceLineNumber AS LONG
END TYPE
DIM SHARED nLabels, Labels_Ubound
Labels_Ubound = 100
REDIM SHARED Labels(1 TO Labels_Ubound) AS Label_Type
DIM SHARED Empty_Label AS Label_Type

DIM SHARED PossibleSubNameLabels AS STRING 'format: name+sp+name+sp+name <-ucase$'d
DIM SHARED SubNameLabels AS STRING 'format: name+sp+name+sp+name <-ucase$'d
DIM SHARED CreatingLabel AS LONG

DIM SHARED AllowLocalName AS LONG

DIM SHARED DataOffset

DIM SHARED prepass


DIM SHARED autoarray

DIM SHARED ontimerid, onkeyid, onstrigid

DIM SHARED revertmaymusthave(1 TO 10000)
DIM SHARED revertmaymusthaven

DIM SHARED linecontinuation

DIM SHARED dim2typepassback AS STRING 'passes back correct case sensitive version of type


DIM SHARED inclevel
DIM SHARED incname(100) AS STRING 'must be full path as given
DIM SHARED inclinenumber(100) AS LONG
DIM SHARED incerror AS STRING

'Magic constant used to replace . in elements when it is not a UDT access
DIM SHARED fix046 AS STRING
fix046$ = "__" + "ASCII" + "_" + "CHR" + "_" + "046" + "__" 'broken up to avoid detection for layout reversion

DIM SHARED layout AS STRING 'passed to IDE
DIM SHARED layoutok AS LONG 'tracks status of entire line

DIM SHARED layoutcomment AS STRING
DIM SHARED layoutcontinuations AS STRING 'Any physical lines logically part of the current line

DIM SHARED tlayout AS STRING 'temporary layout string set by supporting functions
DIM SHARED layoutdone AS LONG 'tracks status of single command


DIM SHARED fooindwel

DIM SHARED isalpha(255)
DIM SHARED isnumeric(255)
DIM SHARED alphanumeric(255)
FOR i = 48 TO 57
    isnumeric(i) = _TRUE
    alphanumeric(i) = _TRUE
NEXT
FOR i = 65 TO 90
    isalpha(i) = _TRUE
    alphanumeric(i) = _TRUE
NEXT
FOR i = 97 TO 122
    isalpha(i) = _TRUE
    alphanumeric(i) = _TRUE
NEXT
'_ is treated as an alphabet letter
isalpha(95) = _TRUE
alphanumeric(95) = _TRUE


DIM SHARED lfsinglechar(255)
lfsinglechar(40) = 1 '(
lfsinglechar(41) = 1 ')
lfsinglechar(42) = 1 '*
lfsinglechar(43) = 1 '+
lfsinglechar(45) = 1 '-
lfsinglechar(47) = 1 '/
lfsinglechar(60) = 1 '<
lfsinglechar(61) = 1 '=
lfsinglechar(62) = 1 '>
lfsinglechar(92) = 1 '\
lfsinglechar(94) = 1 '^

lfsinglechar(44) = 1 ',
lfsinglechar(46) = 1 '.
lfsinglechar(58) = 1 ':
lfsinglechar(59) = 1 ';

lfsinglechar(35) = 1 '# (file no only)
lfsinglechar(36) = 1 '$ (metacommand only)
lfsinglechar(63) = 1 '? (print macro)
lfsinglechar(95) = 1 '_










DIM SHARED nextrunlineindex AS LONG

DIM SHARED lineinput3buffer AS STRING
DIM SHARED lineinput3index AS LONG

DIM SHARED dimstatic AS LONG

DIM SHARED staticarraylist AS STRING
DIM SHARED staticarraylistn AS LONG
DIM SHARED udt_alloc_dynmode AS LONG
DIM SHARED commonarraylist AS STRING
DIM SHARED commonarraylistn AS LONG

'UDT
'names
DIM SHARED lasttype AS LONG
DIM SHARED lasttypeelement AS LONG

TYPE idstruct

    n AS STRING * 256 'name
    cn AS STRING * 256 'case sensitive version of n

    arraytype AS LONG 'similar to t
    arrayelements AS INTEGER
    staticarray AS INTEGER 'set for arrays declared in the main module with static elements
    ' Each TYPE graph has one declaration-selected physical layout:
    ' mode 0 is inline-only; mode 1 is the canonical descriptor-aware layout used when
    ' the graph contains an explicit _Dynamic member array. DIM, REDIM and call sites
    ' never choose or upgrade this mode.
    dynudt AS INTEGER 'non-zero when this UDT scalar/array requires descriptor-aware lifecycle handling
    dynudtmode AS INTEGER '0 inline-only, 1 canonical descriptor-aware layout

    mayhave AS STRING * 8 'mayhave and musthave are exclusive of each other
    musthave AS STRING * 8
    t AS LONG 'type

    tsize AS LONG


    subfunc AS INTEGER 'if function=1, sub=2 (max 100 arguments)
    Dependency AS INTEGER
    internal_subfunc AS INTEGER

    callname AS STRING * 256
    ccall AS INTEGER
    overloaded AS _BYTE
    args AS INTEGER
    minargs AS INTEGER
    arg AS STRING * 400 'similar to t
    argsize AS STRING * 400 'similar to tsize (used for fixed length strings)
    specialformat AS STRING * 256
    secondargmustbe AS STRING * 256
    secondargcantbe AS STRING * 256
    ret AS LONG 'the value it returns if it is a function (again like t)

    insubfunc AS STRING * 256
    insubfuncn AS LONG

    share AS INTEGER
    nele AS STRING * 100
    nelereq AS STRING * 100
    ' Canonical physical-layout mode for each UDT parameter: 0 inline-only, 1
    ' descriptor-aware. It comes from the declared TYPE graph, never from call sites.
    dynudtargmode AS STRING * 100 'per SUB/FUNCTION UDT array/scalar argument canonical layout mode
    linkid AS LONG
    linkarg AS INTEGER
    staticscope AS INTEGER
    'For variables which are arguments passed to a sub/function
    sfid AS LONG 'id number of variable's parent sub/function
    sfarg AS INTEGER 'argument/parameter # within call (1=first)

    hr_syntax AS STRING
END TYPE

DIM SHARED id AS idstruct

DIM SHARED idn AS LONG
DIM SHARED ids_max AS LONG
ids_max = 1024
REDIM SHARED ids(1 TO ids_max) AS idstruct
REDIM SHARED cmemlist(1 TO ids_max + 1) AS INTEGER 'variables that must be in cmem
REDIM SHARED sfcmemargs(1 TO ids_max + 1) AS STRING * 100 's/f arg that must be in cmem
REDIM SHARED arrayelementslist(1 TO ids_max + 1) AS INTEGER 'arrayelementslist (like cmemlist) helps to resolve the number of elements in arrays with an unknown number of elements. Note: arrays with an unknown number of elements have .arrayelements=-1


'create blank id template for idclear to copy (stops strings being set to chr$(0))
DIM SHARED cleariddata AS idstruct
cleariddata.cn = ""
cleariddata.n = ""
cleariddata.mayhave = ""
cleariddata.musthave = ""
cleariddata.callname = ""
cleariddata.arg = ""
cleariddata.argsize = ""
cleariddata.specialformat = ""
cleariddata.secondargmustbe = ""
cleariddata.secondargcantbe = ""
cleariddata.insubfunc = ""
cleariddata.nele = ""
cleariddata.nelereq = ""
cleariddata.dynudtargmode = ""

DIM SHARED gosubid AS LONG
DIM SHARED redimoption AS INTEGER
DIM SHARED dimoption AS INTEGER
DIM SHARED arraydesc AS LONG 'holds currentid
DIM SHARED qberrorhappened AS INTEGER
DIM SHARED qberrorcode AS INTEGER
DIM SHARED qberrorline AS INTEGER
'COMMON SHARED defineaz() AS STRING
'COMMON SHARED defineextaz() AS STRING

DIM SHARED sourcefile AS STRING 'the full path and filename
DIM SHARED file AS STRING 'name of the file (without .bas or path)

'COMMON SHARED separgs() AS STRING

DIM SHARED constequation AS INTEGER
DIM SHARED DynamicMode AS INTEGER
DIM SHARED findidsecondarg AS STRING
DIM SHARED findanotherid AS INTEGER
DIM SHARED findidinternal AS LONG
DIM SHARED currentid AS LONG 'is the index of the last ID accessed
DIM SHARED linenumber AS LONG, reallinenumber AS LONG, totallinenumber AS LONG, definingtypeerror AS LONG
DIM SHARED wholeline AS STRING
DIM SHARED firstLineNumberLabelvWatch AS LONG, lastLineNumberLabelvWatch AS LONG
DIM SHARED vWatchUsedLabels AS STRING, vWatchUsedSkipLabels AS STRING
DIM SHARED linefragment AS STRING

DIM SHARED arrayprocessinghappened AS INTEGER
DIM SHARED stringprocessinghappened AS INTEGER
DIM SHARED cleanupstringprocessingcall AS STRING
DIM SHARED inputfunctioncalled AS _BYTE
DIM SHARED recompile AS INTEGER 'forces recompilation
'COMMON SHARED cmemlist() AS INTEGER

DIM SHARED optionbase AS INTEGER
'During the preprocessing TYPE pass, OPTION BASE has not been applied to the main
'compiler state yet. We track the source-order value separately so TYPE member-array
'bounds can use the same implicit lower bound as normal arrays declared at that point.

'You can't merge it into a common variable!!! Otherwise, Option Base 1
'will be screwed up for normal fields!!!!!! If use coomon variabler for both,
'then Option Base 1 is applied also to previous arrays and:
'Dim A (3) as long : Option Base 1: Print Lbound (a) return 1!
DIM SHARED udtparse_optionbase AS INTEGER


DIM SHARED addmetastatic AS INTEGER
DIM SHARED addmetadynamic AS INTEGER
DIM SHARED addmetainclude AS STRING
DIM SHARED autoIncludingFile AS INTEGER
DIM SHARED autoIncForceUScore AS INTEGER

DIM SHARED module AS STRING

DIM SHARED subfunc AS STRING
DIM SHARED subfuncn AS LONG
DIM SHARED subfuncnlast AS LONG
DIM SHARED subfuncid AS LONG

DIM SHARED defdatahandle AS INTEGER
DIM SHARED dimsfarray AS INTEGER
DIM SHARED dimshared AS INTEGER

'Allows passing of known elements to recompilation
DIM SHARED sflistn AS INTEGER
'COMMON SHARED sfidlist() AS LONG
'COMMON SHARED sfarglist() AS INTEGER
'COMMON SHARED sfelelist() AS INTEGER
DIM SHARED glinkid AS LONG
DIM SHARED glinkarg AS INTEGER
' Current SUB/FUNCTION argument UDT layout mode while dim2() registers argument IDs.
' The value comes from the parameter TYPE declaration and is deterministic.
DIM SHARED sf_udt_dynmode AS INTEGER
DIM SHARED typname2typsize AS LONG
DIM SHARED uniquenumbern AS LONG
'When this flag is enabled, a TYPE member array may be referenced without an
'explicit element index. This whole-array form carries enough metadata for later
'code to distinguish an inline block (unmarked/_Static) from an explicit _Dynamic
'descriptor slot. It is enabled only for LBOUND/UBOUND, ERASE, _OFFSET, the _MEM
'family, and array-argument contexts.
'
'In normal expression evaluation this remains disabled, because those contexts
'refer to a single array element and therefore still require an explicit index.


DIM SHARED udt_allow_bare_array AS INTEGER

'CLEAR , , 16384


DIM SHARED bitmask(1 TO 64) AS _INTEGER64
DIM SHARED bitmaskinv(1 TO 64) AS _INTEGER64

DIM SHARED defineextaz(1 TO 27) AS STRING
DIM SHARED defineaz(1 TO 27) AS STRING '27 is an underscore







DIM SHARED statementn AS LONG
DIM SHARED everycasenewcase AS LONG




DIM SHARED controllevel AS INTEGER '0=not in a control block
DIM SHARED controltype(1000) AS INTEGER
'1=IF (awaiting END IF)
'2=FOR (awaiting NEXT)
'3=DO (awaiting LOOP [UNTIL|WHILE param])
'4=DO WHILE/UNTIL (awaiting LOOP)
'5=WHILE (awaiting WEND)
'6=$IF (precompiler)
'10=SELECT CASE qbs (awaiting END SELECT/CASE)
'11=SELECT CASE int64 (awaiting END SELECT/CASE)
'12=SELECT CASE uint64 (awaiting END SELECT/CASE)
'13=SELECT CASE LONG double (awaiting END SELECT/CASE/CASE ELSE)
'14=SELECT CASE float ...
'15=SELECT CASE double
'16=SELECT CASE int32
'17=SELECT CASE uint32
'18=CASE (awaiting END SELECT/CASE/CASE ELSE)
'19=CASE ELSE (awaiting END SELECT)
'32=SUB/FUNCTION (awaiting END SUB/FUNCTION)
DIM controlid(1000) AS LONG
DIM controlvalue(1000) AS LONG
DIM controlstate(1000) AS INTEGER
DIM SHARED controlref(1000) AS LONG 'the line number the control was created on

'
' Collection of flags indicating which unstable features should be used during compilation
'
REDIM SHARED unstableFlags(1 TO 3) AS _BYTE
DIM UNSTABLE_MIDI: UNSTABLE_MIDI = 1
DIM UNSTABLE_HTTP: UNSTABLE_HTTP = 2
DIM SHARED UNSTABLE_TYPEFIELDS AS LONG: UNSTABLE_TYPEFIELDS = 3



ON ERROR GOTO qberror

i2&& = 1
FOR i&& = 1 TO 64
    bitmask(i&&) = i2&&
    bitmaskinv(i&&) = NOT i2&&
    i2&& = i2&& + 2 ^ i&&
NEXT

DIM id2 AS idstruct

cleanupstringprocessingcall$ = "qbs_cleanup(qbs_tmp_base,"

REDIM SHARED sfidlist(1000) AS LONG
REDIM SHARED sfarglist(1000) AS INTEGER
REDIM SHARED sfelelist(1000) AS INTEGER















'----------------ripgl.bas--------------------------------------------------------------------------------
gl_scan_header
'----------------ripgl.bas--------------------------------------------------------------------------------







'-----------------------QB64 COMPILER ONCE ONLY SETUP CODE ENDS HERE---------------------------------------

IF NoIDEMode THEN IDEAutoPosition = _FALSE: GOTO noide
DIM FileDropEnabled AS _BYTE
IF NOT FileDropEnabled THEN FileDropEnabled = _TRUE: _ACCEPTFILEDROP

IF IDEAutoPosition AND NOT IDEBypassAutoPosition THEN _SCREENMOVE IDELeftPosition, IDETopPosition
idemode = 1
sendc$ = "" 'no initial message
IF CMDLineSrcFile$ <> "" THEN sendc$ = CHR$(1) + CMDLineSrcFile$
sendcommand:
idecommand$ = sendc$
C = ide(0)
ideerror = 0
IF C = 0 THEN idemode = 0: GOTO noide
c$ = idereturn$

IF C = 2 THEN 'begin
    ideerrorline = 0 'addresses invalid prepass error line numbers being reported
    idepass = 1
    GOTO fullrecompile
    ideret1:
    wholeline$ = c$
    GOTO ideprepass
    ideret2:
    IF lastLineReturn THEN GOTO lastLineReturn
    sendc$ = CHR$(3) 'request next line
    GOTO sendcommand
END IF

IF C = 4 THEN 'next line
    IF idepass = 1 THEN
        wholeline$ = c$
        GOTO ideprepass
        '(returns to ideret2: above)
    END IF
    'assume idepass>1
    a3$ = c$
    continuelinefrom = 0
    GOTO compileline 'Will execute compilation of 1 line then come back to ideret4
    ideret4:
    IF lastLineReturn THEN GOTO lastLineReturn
    sendc$ = CHR$(3) 'request next line
    GOTO sendcommand
END IF

IF C = 5 THEN 'end of program reached
    lastLine = 1
    lastLineReturn = 1
    IF idepass = 1 THEN
        wholeline$ = ""
        GOTO ideprepass
        '(returns to ideret2: above, then to lastLineReturn below)
    END IF
    'idepass>1
    a3$ = ""
    continuelinefrom = 0
    GOTO compileline 'Will execute compilation of 1 line then come back to lastLineReturn
    lastLineReturn:
    lastLineReturn = 0
    lastLine = 0

    IF idepass = 1 THEN
        'prepass complete
        idepass = 2
        GOTO ide3
        ideret3:
        sendc$ = CHR$(7) 'repass request
        firstLine = 1
        GOTO sendcommand
    END IF
    'assume idepass=2
    'finalize program
    GOTO ide5
    ideret5: 'note: won't return here if a recompile was required!
    sendc$ = CHR$(6) 'ready
    idecompiled = 0
    GOTO sendcommand
END IF

IF C = 9 THEN 'run

    IF idecompiled = 0 THEN 'exe needs to be compiled
        file$ = c$

        'locate accessible file and truncate
        f$ = file$

        path.exe$ = DefaultExeSaveFolder$
        IF SaveExeWithSource THEN
            IF LEN(ideprogname) THEN path.exe$ = idepath$ + pathsep$
        END IF

        i = 1
        nextexeindex:
        IF _FILEEXISTS(path.exe$ + file$ + extension$) THEN
            E = 0
            ON ERROR GOTO qberror_test
            KILL path.exe$ + file$ + extension$
            ON ERROR GOTO qberror
            IF E = 1 THEN
                i = i + 1
                file$ = f$ + "(" + _TOSTR$(i) + ")"
                GOTO nextexeindex
            END IF
        END IF

        'inform IDE of name change if necessary (IDE will respond with message 9 and corrected name)
        IF i <> 1 THEN
            sendc$ = CHR$(12) + file$
            GOTO sendcommand
        END IF

        ideerrorline = 0 'addresses C++ comp. error's line number
        GOTO ide6
        ideret6:
        idecompiled = 1
    END IF

    IF iderunmode = 2 THEN
        sendc$ = CHR$(11) '.EXE file created
        GOTO sendcommand
    END IF

    'execute program

    IF LoggingEnabled THEN
        ENVIRON "QB64PE_LOG_LEVEL=" + LogMinLevel$
        ENVIRON "QB64PE_LOG_SCOPES=" + LogScopes$
        ENVIRON "QB64PE_LOG_HANDLERS=" + LogHandlers$
        ENVIRON "QB64PE_LOG_FILE_PATH=" + LogFileName$
    ELSE
        ENVIRON "QB64PE_LOG_LEVEL="
        ENVIRON "QB64PE_LOG_SCOPES="
        ENVIRON "QB64PE_LOG_HANDLERS="
        ENVIRON "QB64PE_LOG_FILE_PATH="
    END IF

    ExecuteLine$ = ""

    IF MacOSX THEN
        IF path.exe$ = "" THEN path.exe$ = "./"

        IF LEFT$(lastBinaryGenerated$, LEN(path.exe$)) = path.exe$ THEN
            ExecuteName$ = _FULLPATH$(lastBinaryGenerated$)
        ELSE
            ExecuteName$ = _FULLPATH$(path.exe$ + lastBinaryGenerated$)
        END IF

        IF path.exe$ = "./" THEN path.exe$ = ""

        IF GetRCStateVar(ConsoleOn) > 0 OR LoggingEnabled THEN 'needed for all handlers, hence LoggingEnabled instead LogToConsole

            generateMacOSLogScript ExecuteName$, ModifyCOMMAND$, tmpdir$ + "log.command"

            ' Spawning a program in a terminal is done via `open`.
            ' We have to use a separate script to be able to set environment variables for the program
            ExecuteLine$ = "open -b com.apple.terminal " + _CHR_QUOTE + tmpdir$ + "log.command" + _CHR_QUOTE
            ExecuteLine$ = ExecuteLine$ + _IIF(LogToConsole, " && read -rsn1 -p 'Press any key...'; echo", "")
        ELSE
            ExecuteLine$ = QuotedFilename$(ExecuteName$) + ModifyCOMMAND$
        END IF
    ELSEIF os$ = "WIN" THEN
        IF GetRCStateVar(ConsoleOn) > 0 OR LogToConsole THEN
            prefix$ = "cmd /c " + _CHR_QUOTE: suffix$ = _IIF(LogToConsole, _CHR_QUOTE + " & pause", _CHR_QUOTE)
        ELSE
            prefix$ = "": suffix$ = ""
        END IF

        ExecuteLine$ = prefix$ + QuotedFilename$(_FULLPATH$(lastBinaryGenerated$)) + ModifyCOMMAND$ + suffix$
    ELSEIF os$ = "LNX" THEN
        IF path.exe$ = "" THEN path.exe$ = "./"

        IF GetRCStateVar(ConsoleOn) > 0 OR LogToConsole THEN
            ExecuteLine$ = DefaultTerminal$

            IF LEFT$(lastBinaryGenerated$, LEN(path.exe$)) = path.exe$ THEN
                ExecuteLine$ = StrReplace$(ExecuteLine$, "$$", QuotedFilename$(_FULLPATH$(lastBinaryGenerated$)))
            ELSE
                ExecuteLine$ = StrReplace$(ExecuteLine$, "$$", QuotedFilename$(_FULLPATH$(path.exe$ + lastBinaryGenerated$)))
            END IF

            ExecuteLine$ = StrReplace$(ExecuteLine$, "$@", ModifyCOMMAND$)
            ExecuteLine$ = ExecuteLine$ + _IIF(LogToConsole, " && read -rsn1 -p 'Press any key...'; echo", "")
        ELSE
            IF LEFT$(lastBinaryGenerated$, LEN(path.exe$)) = path.exe$ THEN
                ExecuteLine$ = QuotedFilename$(_FULLPATH$(lastBinaryGenerated$)) + ModifyCOMMAND$
            ELSE
                ExecuteLine$ = QuotedFilename$(_FULLPATH$(path.exe$ + lastBinaryGenerated$)) + ModifyCOMMAND$
            END IF
        END IF

        IF path.exe$ = "./" THEN path.exe$ = ""
    END IF

    IF iderunmode = 1 THEN
        IF NoExeSaved THEN
            'This is the section which deals with if the user selected to run the program without
            'saving an EXE file to the disk.
            'We start off by first running the EXE, and then we delete it from the drive.
            'making it a temporary file when all is said and done.
            SHELL ExecuteLine$

            IF os$ = "WIN" THEN
                SHELL _HIDE _DONTWAIT "del " + QuotedFilename$(CHR$(34) + lastBinaryGenerated$ + CHR$(34)) 'kill it
            END IF
            IF path.exe$ = "" THEN path.exe$ = "./"
            IF os$ = "LNX" THEN
                IF LEFT$(lastBinaryGenerated$, LEN(path.exe$)) = path.exe$ THEN
                    KILL lastBinaryGenerated$
                ELSE
                    KILL path.exe$ + lastBinaryGenerated$
                END IF
            END IF
            IF path.exe$ = "./" THEN path.exe$ = ""
            NoExeSaved = _FALSE 'reset the flag for a temp EXE
            sendc$ = CHR$(6) 'ready
            GOTO sendcommand
        END IF

        SHELL _DONTWAIT ExecuteLine$
    ELSE
        SHELL ExecuteLine$

        DO: LOOP UNTIL INKEY$ = ""
        DO: LOOP UNTIL _KEYHIT = 0
    END IF

    IF idemode THEN
        'Darken fg/bg colors
        dummy = DarkenFGBG(0)
    END IF

    IF GetRCStateVar(vWatchOn) THEN
        sendc$ = CHR$(254) 'launch debug interface
    ELSE
        sendc$ = CHR$(6) 'ready
    END IF
    GOTO sendcommand
END IF

IF C = 14 THEN
    a$ = "$NOPREFIX is a deprecated feature, QB64(PE) specific keywords MUST have the underscore"
    GOTO errmes
END IF

PRINT "Invalid IDE message": END

ideerror:
IF INSTR(idemessage$, sp$) THEN
    'Something went wrong here, so let's give a generic error message to the user.
    '(No error message should contain sp$ - that is, CHR$(13), when not in Debug mode)
    terrmsg$ = _ERRORMESSAGE$
    IF terrmsg$ = "No error" THEN terrmsg$ = "Internal error"
    idemessage$ = "Compiler error (check for syntax errors) (" + terrmsg$ + ":"
    IF ERR THEN idemessage$ = idemessage$ + _TOSTR$(ERR) + "-"
    IF _ERRORLINE THEN idemessage$ = idemessage$ + _TOSTR$(_ERRORLINE)
    IF _INCLERRORLINE THEN idemessage$ = idemessage$ + "-" + _INCLERRORFILE$ + "-" + _TOSTR$(_INCLERRORLINE)
    idemessage$ = idemessage$ + ")"
    IF inclevel > 0 THEN idemessage$ = idemessage$ + incerror$
END IF

sendc$ = CHR$(8) + idemessage$ + MKL$(ideerrorline)
GOTO sendcommand


noide:
IF (NOT QB64VersionPrinted OR NOT ConsoleMode) AND NOT QuietMode THEN
    QB64VersionPrinted = _TRUE
    PRINT "QB64-PE Compiler V" + Version$
END IF

IF CMDLineSrcFile$ = "" THEN
    LINE INPUT ; "COMPILE (.bas)>", f$
ELSE
    f$ = CMDLineSrcFile$
END IF

f$ = LTRIM$(RTRIM$(f$))

IF FileHasExtension(f$) = 0 THEN f$ = f$ + ".bas"

sourcefile$ = f$
CMDLineSrcFile$ = sourcefile$
'derive name from sourcefile
f$ = RemoveFileExtension$(f$)

path.exe$ = DefaultExeSaveFolder$
currentdir$ = _CWD$
path.source$ = getfilepath$(sourcefile$)
IF LEN(path.source$) THEN
    IF _DIREXISTS(path.source$) = 0 THEN
        PRINT
        PRINT "Cannot locate source file: " + sourcefile$
        IF ConsoleMode THEN SYSTEM 1
        END 1
    END IF
    CHDIR path.source$
    path.source$ = _CWD$
    IF RIGHT$(path.source$, 1) <> pathsep$ THEN path.source$ = path.source$ + pathsep$
    CHDIR currentdir$
END IF
IF SaveExeWithSource THEN path.exe$ = path.source$

FOR x = LEN(f$) TO 1 STEP -1
    a$ = MID$(f$, x, 1)
    IF a$ = "/" OR a$ = "\" THEN
        f$ = RIGHT$(f$, LEN(f$) - x)
        EXIT FOR
    END IF
NEXT
file$ = f$

'if cmemlist(currentid+1)<>0 before calling regid the variable
'MUST be defined in cmem!

fullrecompile:

IF idemode = 0 AND NOT QuietMode THEN
    PRINT
    PRINT "Beginning C++ output from QB64 code... "
END IF

FOR i = 1 TO UBOUND(DEPENDENCY): DEPENDENCY(i) = 0: NEXT

Error_Happened = 0

FOR closeall = 1 TO 300: CLOSE closeall: NEXT

OPEN tmpdir$ + "temp.bin" FOR OUTPUT LOCK WRITE AS #26 'relock

bh = OpenBuffer%("O", tmpdir$ + "dyninfo.txt")

IF Debug THEN CLOSE #9: OPEN tmpdir$ + "debug.txt" FOR OUTPUT AS #9

FOR i = 1 TO ids_max + 1
    arrayelementslist(i) = 0
    cmemlist(i) = 0
    sfcmemargs(i) = ""
NEXT

'erase cmemlist
'erase sfcmemargs

lastunresolved = -1 'first pass
sflistn = -1 'no entries

SubNameLabels = sp 'QB64 will perform a repass to resolve sub names used as labels

'Reset used libraries tracking list (fullrecompile only)
REDIM SHARED useLibList$(4, 10)

'RCStateVars (feature and required recompile tracking)
ClearRCStateVar ColorSet
ClearRCStateVar OptExpl: IF ForceOptExpl THEN ForceRCStateVar OptExpl, 1
ClearRCStateVar OptExplArr
ClearRCStateVar AssertsOn
ClearRCStateVar ConsoleOn
ClearRCStateVar vWatchOn
ClearRCStateVar SockDepOn
ClearRCStateVar ErrorLocationMode

'--------------------
recompile:
recompile = 0 'reset stray flag

ExecuteRCStateVar ColorSet
ExecuteRCStateVar OptExpl
ExecuteRCStateVar OptExplArr
ExecuteRCStateVar AssertsOn
ExecuteRCStateVar ConsoleOn
ExecuteRCStateVar vWatchOn
vWatchVariable "", -1 'reset internal variables list
ExecuteRCStateVar SockDepOn
ExecuteRCStateVar ErrorLocationMode

lastLineReturn = 0
lastLine = 0
firstLine = 1
mainEndLine = 0
autoIncludeBuffer = -1

UseGL = 0

Error_Happened = 0

HashClear 'clear the hash table

'add reserved words to hashtable

f = HASHFLAG_TYPE + HASHFLAG_RESERVED
HashAdd "_UNSIGNED", f, 0
HashAdd "_BIT", f, 0
HashAdd "_BYTE", f, 0
HashAdd "INTEGER", f, 0
HashAdd "LONG", f, 0
HashAdd "_INTEGER64", f, 0
HashAdd "_OFFSET", f, 0
HashAdd "SINGLE", f, 0
HashAdd "DOUBLE", f, 0
HashAdd "_FLOAT", f, 0
HashAdd "STRING", f, 0
HashAdd "ANY", f, 0

f = HASHFLAG_OPERATOR + HASHFLAG_RESERVED
HashAdd "NOT", f, 0
HashAdd "IMP", f, 0
HashAdd "EQV", f, 0
HashAdd "AND", f, 0
HashAdd "OR", f, 0
HashAdd "XOR", f, 0
HashAdd "MOD", f, 0
HashAdd "_NEGATE", f, 0
HashAdd "_ANDALSO", f, 0
HashAdd "_ORELSE", f, 0

f = HASHFLAG_RESERVED + HASHFLAG_CUSTOMSYNTAX
HashAdd "LIST", f, 0
HashAdd "BASE", f, 0
HashAdd "_EXPLICIT", f, 0
HashAdd "_EXPLICITARRAY", f, 0
HashAdd "AS", f, 0
HashAdd "IS", f, 0
HashAdd "OFF", f, 0
HashAdd "ON", f, 0
HashAdd "STOP", f, 0
HashAdd "TO", f, 0
HashAdd "USING", f, 0
HashAdd "_DYNAMIC", f, 0
HashAdd "_STATIC", f, 0
'PUT(graphics) statement:
HashAdd "PRESET", f, 0
HashAdd "PSET", f, 0
'OPEN statement:
HashAdd "FOR", f, 0
HashAdd "OUTPUT", f, 0
HashAdd "RANDOM", f, 0
HashAdd "BINARY", f, 0
HashAdd "APPEND", f, 0
HashAdd "SHARED", f, 0
HashAdd "ACCESS", f, 0
HashAdd "LOCK", f, 0
HashAdd "READ", f, 0
HashAdd "WRITE", f, 0
'LINE statement:
HashAdd "STEP", f, 0
'WIDTH statement:
HashAdd "LPRINT", f, 0
'VIEW statement:
HashAdd "PRINT", f, 0

f = HASHFLAG_RESERVED + HASHFLAG_XELEMENTNAME + HASHFLAG_XTYPENAME
'A
'B
'C
HashAdd "COMMON", f, 0
HashAdd "CALL", f, 0
HashAdd "CASE", f - HASHFLAG_XELEMENTNAME, 0
HashAdd "COM", f, 0 '(ON...)
HashAdd "CONST", f, 0
'D
HashAdd "DATA", f, 0
HashAdd "DECLARE", f, 0
HashAdd "DEF", f, 0
HashAdd "DEFDBL", f, 0
HashAdd "DEFINT", f, 0
HashAdd "DEFLNG", f, 0
HashAdd "DEFSNG", f, 0
HashAdd "DEFSTR", f, 0
HashAdd "DIM", f, 0
HashAdd "DO", f - HASHFLAG_XELEMENTNAME, 0
'E
HashAdd "ERROR", f - HASHFLAG_XELEMENTNAME, 0 '(ON ...)
HashAdd "ELSE", f, 0
HashAdd "ELSEIF", f, 0
HashAdd "ENDIF", f, 0
HashAdd "EXIT", f - HASHFLAG_XELEMENTNAME, 0
'F
HashAdd "FIELD", f - HASHFLAG_XELEMENTNAME, 0
HashAdd "FUNCTION", f, 0
'G
HashAdd "GOSUB", f, 0
HashAdd "GOTO", f, 0
'H
'I
HashAdd "INPUT", f - HASHFLAG_XELEMENTNAME - HASHFLAG_XTYPENAME, 0 '(INPUT$ function exists, so conflicts if allowed as custom syntax)
HashAdd "IF", f, 0
'K
HashAdd "KEY", f - HASHFLAG_XELEMENTNAME - HASHFLAG_XTYPENAME, 0 '(ON...)
'L
HashAdd "LET", f - HASHFLAG_XELEMENTNAME, 0
HashAdd "LOOP", f - HASHFLAG_XELEMENTNAME, 0
HashAdd "LEN", f - HASHFLAG_XELEMENTNAME, 0 '(LEN function exists, so conflicts if allowed as custom syntax)
'M
'N
HashAdd "NEXT", f - HASHFLAG_XELEMENTNAME, 0
'O
'P
HashAdd "PLAY", f - HASHFLAG_XELEMENTNAME - HASHFLAG_XTYPENAME, 0 '(ON...)
HashAdd "PEN", f - HASHFLAG_XELEMENTNAME - HASHFLAG_XTYPENAME, 0 '(ON...)
'Q
'R
HashAdd "REDIM", f, 0
HashAdd "REM", f, 0
HashAdd "RESTORE", f - HASHFLAG_XELEMENTNAME, 0
HashAdd "RESUME", f - HASHFLAG_XELEMENTNAME, 0
HashAdd "RETURN", f - HASHFLAG_XELEMENTNAME, 0
HashAdd "RUN", f - HASHFLAG_XELEMENTNAME, 0
'S
HashAdd "STATIC", f, 0
HashAdd "STRIG", f, 0 '(ON...)
HashAdd "SEG", f, 0
HashAdd "SELECT", f - HASHFLAG_XELEMENTNAME - HASHFLAG_XTYPENAME, 0
HashAdd "SUB", f, 0
HashAdd "SCREEN", f - HASHFLAG_XELEMENTNAME - HASHFLAG_XTYPENAME, 0
'T
HashAdd "THEN", f, 0
HashAdd "TIMER", f - HASHFLAG_XELEMENTNAME - HASHFLAG_XTYPENAME, 0 '(ON...)
HashAdd "TYPE", f - HASHFLAG_XELEMENTNAME, 0
'U
HashAdd "UNTIL", f, 0
HashAdd "UEVENT", f, 0
'V
'W
HashAdd "WEND", f, 0
HashAdd "WHILE", f, 0
'X
'Y
'Z







'clear/init variables
CheckingOn = 1
ScreenHideOn = 0
ResizeOn = 0: ResizeScale = 0
ResolveStaticFunctions = 0
dynamiclibrary = 0
dimsfarray = 0
dimstatic = 0
AllowLocalName = 0
PossibleSubNameLabels = sp 'QB64 will perform a repass to resolve sub names used as labels
use_global_byte_elements = 0
dimshared = 0: dimmethod = 0: dimoption = 0: redimoption = 0: commonoption = 0
mylib$ = "": mylibopt$ = ""
declaringlibrary = 0
nLabels = 0
dynscope = 0
elsefollowup = 0
ontimerid = 0: onkeyid = 0: onstrigid = 0
commonarraylist = "": commonarraylistn = 0
staticarraylist = "": staticarraylistn = 0
fooindwel = 0
layout = ""
layoutok = 0
inclevel = 0
errorLineInInclude = 0
addmetainclude$ = ""
nextrunlineindex = 1
lasttype = 0
lasttypeelement = 0
REDIM SHARED udtxname(1000) AS STRING * 256
REDIM SHARED udtxcname(1000) AS STRING * 256
REDIM SHARED udtxsize(1000) AS LONG
REDIM SHARED udtxfdynsize(1000) AS LONG 'TYPE size for its canonical descriptor-aware layout
REDIM SHARED udtxcanonmode(1000) AS INTEGER '0 inline-only, 1 canonical descriptor-aware layout
REDIM SHARED udtxnext(1000) AS LONG
REDIM SHARED udtxvariable(1000) AS INTEGER 'true if the udt contains variable length elements

'TYPE element metadata tables.
'
'Each TYPE member is assigned an element index member_element_id. These parallel arrays store the
'compile-time metadata for that member.
'
'  udtename(member_element_id)
'      QB source name of the member.
'
'  udtecname(member_element_id)
'      Generated C field name for the member.
'
'  udtesize(member_element_id)
'      Declaration-time inline storage size of the member in bits.
'      For non-array members this is the size of one value. For every declared member
'      array it is element_size * declared_element_count. An explicit _Dynamic member
'      uses a pointer-sized slot in the canonical descriptor layout; that size is kept
'      separately in udtefdynsize().
'
'  udtetype(member_element_id)
'      Encoded QB type id plus flags (ISUDT, ISSTRING, ISFIXEDLENGTH, etc.).
'
'  udtetypesize(member_element_id)
'      Auxiliary size/type metadata returned by typname2typsize().
'      For fixed-length strings this is the fixed string length.
'      For other member kinds this stores the extra per-type metadata returned by
'      the type resolver when the member was declared.
'
'  udtearrayelements(member_element_id)
'      Declaration-time element count for every TYPE member array.
'      This is the product of all declared dimension sizes. For _Dynamic it is the
'      initial count used when the live descriptor is created. Zero means not an array.
'
'  udtearraybase(member_element_id)
'      Lower bound of the first dimension only.
'      This field is kept as a convenience / compatibility value.
'      For multidimensional TYPE member arrays, udtearraydesc(E) is authoritative.
'
'  udtearraydims(member_element_id)
'      Number of declared dimensions in the TYPE member array.
'      Zero means the member is not an array.
'
'  udtearraydesc(member_element_id)
'      Serialized declaration-time bounds metadata for a TYPE member array.
'      Format:
'
'          "<lower1>,<count1>;<lower2>,<count2>;...;<lowerN>,<countN>"
'
'      where each pair describes one dimension in source order:
'
'          lowerX = declared lower bound for dimension X
'          countX = number of elements in dimension X
'
'      Notes:
'      - The descriptor stores element counts, not upper bounds.
'      - upper_bound = lower_bound + count - 1
'      - Dimensions are stored in the same order they appeared in source.
'      - This metadata exists for inline and explicit _Dynamic members. For _Dynamic
'        it supplies initial bounds; member REDIM later updates the live runtime descriptor.
'      - This string is compiler metadata, not a normal QB64 runtime array descriptor.
'
'  udtearrayfieldmode(member_element_id)
'      Per-member storage override for TYPE member arrays:
'          0 = unmarked member array; keep declaration-time inline storage
'          1 = _Static; explicitly keep inline storage
'          2 = _Dynamic; store a pointer to a live array descriptor
'      The value is only valid when udtearrayelements(member_element_id) is non-zero.
'
'      Examples:
'
'          a(0 TO 3)              -> "0,4"
'          b(1 TO 10)             -> "1,10"
'          c(-2 TO 2, 5 TO 7)     -> "-2,5;5,3"
'
'  udtenext(member_element_id)
'      Linked-list next-member index for the enclosing TYPE definition.
'      Zero marks the end of the member list.
'
'elements
REDIM SHARED udtename(1000) AS STRING * 256
REDIM SHARED udtecname(1000) AS STRING * 256
REDIM SHARED udtesize(1000) AS LONG
REDIM SHARED udtefdynoffset(1000) AS LONG
REDIM SHARED udtefdynsize(1000) AS LONG
REDIM SHARED udtetype(1000) AS LONG
REDIM SHARED udtetypesize(1000) AS LONG
REDIM SHARED udtearrayelements(1000) AS LONG
REDIM SHARED udtearraybase(1000) AS LONG 'convenience / compatibility field for first dimension only
REDIM SHARED udtearraydims(1000) AS LONG
REDIM SHARED udtearraydesc(1000) AS STRING 'serialized declaration bounds for all dimensions, in source order: "<lower1>,<count1>;<lower2>,<count2>;..."
REDIM SHARED udtearrayfieldmode(1000) AS LONG '0 unmarked inline, 1 explicit _Static inline, 2 explicit _Dynamic descriptor-backed
REDIM SHARED udtenext(1000) AS LONG
' _MEM over descriptor-backed member arrays must be tied to the member descriptor's own
' mem_lock, not only to the parent UDT storage. udtreference$ sets this expression while
' resolving indexed _Dynamic member-array elements; evaluatetotyp$ consumes it in _MEM paths.
DIM SHARED dynmemlockexpr AS STRING 'descriptor lock expression for _MEM over indexed _Dynamic TYPE member arrays
definingtype = 0
definingtypeerror = 0
constlast = -1
addmetastatic = 0
addmetadynamic = 0
DynamicMode = 0
optionbase = 0
udtparse_optionbase = 0
ExeIconSet = 0 '!!! If set, then this is the respective source line number. !!!
VersionInfoSet = _FALSE
viFileVersionNum$ = "": viProductVersionNum$ = "": viCompanyName$ = ""
viFileDescription$ = "": viFileVersion$ = "": viInternalName$ = ""
viLegalCopyright$ = "": viLegalTrademarks$ = "": viOriginalFilename$ = ""
viProductName$ = "": viProductVersion$ = "": viComments$ = "": viWeb$ = ""
DataOffset = 0
statementn = 0
everycasenewcase = 0
qberrorhappened = 0: qberrorcode = 0: qberrorline = 0
FOR i = 1 TO 27: defineaz(i) = "SINGLE": defineextaz(i) = "!": NEXT
controllevel = 0
findidsecondarg$ = "": findanotherid = 0: findidinternal = 0: currentid = 0
linenumber = 0
wholeline$ = ""
linefragment$ = ""
idn = 0
arrayprocessinghappened = 0
stringprocessinghappened = 0
inputfunctioncalled = 0
subfuncn = 0
subfuncnlast = 0
subfunc = ""
SelectCaseCounter = 0
ExecCounter = 0
UserDefineList$ = UserDefineListPresets$
UserDefineCount = UserDefineCountPresets
totalVariablesCreated = 0
typeDefinitions$ = ""
totalMainVariablesCreated = 0
REDIM SHARED usedVariableList(1000) AS usedVarList
totalWarnings = 0
duplicateConstWarning = 0
emptySCWarning = 0
warningListItems = 0
lastWarningHeader = ""
vWatchUsedLabels = SPACE$(1000)
vWatchUsedSkipLabels = SPACE$(1000)
firstLineNumberLabelvWatch = 0
REDIM SHARED warning$(1000)
REDIM SHARED warningLines(1000) AS LONG
REDIM SHARED warningIncLines(1000) AS LONG
REDIM SHARED warningIncFiles(1000) AS STRING
maxLineNumber = 0
uniquenumbern = 0

'import _MEM type
ptrsz = OS_BITS \ 8

lasttype = lasttype + 1: i = lasttype
udtxname(i) = "_MEM"
udtxcname(i) = "_MEM"
udtxsize(i) = ((ptrsz) * 5 + (4) * 2 + (8) * 1) * 8
lasttypeelement = lasttypeelement + 1: i2 = lasttypeelement
udtename(i2) = "OFFSET"
udtecname(i2) = "OFFSET"
udtetype(i2) = OFFSETTYPE: udtesize(i2) = ptrsz * 8
udtetypesize(i2) = 0 'tsize
udtxnext(i) = i2
i3 = i2
lasttypeelement = lasttypeelement + 1: i2 = lasttypeelement
udtename(i2) = "SIZE"
udtecname(i2) = "SIZE"
udtetype(i2) = OFFSETTYPE: udtesize(i2) = ptrsz * 8
udtetypesize(i2) = 0 'tsize
udtenext(i3) = i2
i3 = i2
lasttypeelement = lasttypeelement + 1: i2 = lasttypeelement
udtename(i2) = "$_LOCK_ID"
udtecname(i2) = "$_LOCK_ID"
udtetype(i2) = INTEGER64TYPE: udtesize(i2) = 64
udtetypesize(i2) = 0 'tsize
udtenext(i3) = i2
i3 = i2
lasttypeelement = lasttypeelement + 1: i2 = lasttypeelement
udtename(i2) = "$_LOCK_OFFSET"
udtecname(i2) = "$_LOCK_OFFSET"
udtetype(i2) = OFFSETTYPE: udtesize(i2) = ptrsz * 8
udtetypesize(i2) = 0 'tsize
udtenext(i3) = i2
i3 = i2
lasttypeelement = lasttypeelement + 1: i2 = lasttypeelement
udtename(i2) = "TYPE"
udtecname(i2) = "TYPE"
udtetype(i2) = OFFSETTYPE: udtesize(i2) = ptrsz * 8
udtetypesize(i2) = 0 'tsize
udtenext(i3) = i2
i3 = i2
lasttypeelement = lasttypeelement + 1: i2 = lasttypeelement
udtename(i2) = "ELEMENTSIZE"
udtecname(i2) = "ELEMENTSIZE"
udtetype(i2) = OFFSETTYPE: udtesize(i2) = ptrsz * 8
udtetypesize(i2) = 0 'tsize
udtenext(i3) = i2
udtenext(i2) = 0
i3 = i2
lasttypeelement = lasttypeelement + 1: i2 = lasttypeelement
udtename(i2) = "IMAGE"
udtecname(i2) = "IMAGE"
udtetype(i2) = LONGTYPE: udtesize(i2) = 32
udtetypesize(i2) = 0 'tsize
udtenext(i3) = i2
udtenext(i2) = 0
i3 = i2
lasttypeelement = lasttypeelement + 1: i2 = lasttypeelement
udtename(i2) = "SOUND"
udtecname(i2) = "SOUND"
udtetype(i2) = LONGTYPE: udtesize(i2) = 32
udtetypesize(i2) = 0 'tsize
udtenext(i3) = i2
udtenext(i2) = 0
BuildUDTDynLayout i

'Reset all unstable flags
FOR i = 1 TO UBOUND(unstableFlags): unstableFlags(i) = 0: NEXT

'Reset embedded files tracking list
REDIM SHARED embedFileList$(3, 10)

'External dependencies buffer
DIM SHARED ExtDepBuf: ExtDepBuf = OpenBuffer%("O", tmpdir$ + "extdep.txt")

'The $INCLUDEONCE check buffer
DIM SHARED IncOneBuf: IncOneBuf = OpenBuffer%("O", tmpdir$ + "incone.txt")

'Output for format mode
DIM SHARED FormatBuf: FormatBuf = OpenBuffer%("O", tmpdir$ + "format.out")

'begin compilation
FOR closeall = 1 TO 300: CLOSE closeall: NEXT
OPEN tmpdir$ + "temp.bin" FOR OUTPUT LOCK WRITE AS #26 'relock

bh = OpenBuffer%("O", tmpdir$ + "icon.rc")

IF Debug THEN CLOSE #9: OPEN tmpdir$ + "debug.txt" FOR APPEND AS #9

IF idemode = 0 THEN
    qberrorhappened = -1
    OPEN sourcefile$ FOR INPUT AS #1
    qberrorhappened1:
    IF qberrorhappened = 1 THEN
        PRINT
        PRINT "Cannot locate source file: " + sourcefile$
        IF ConsoleMode THEN SYSTEM 1
        END 1
    ELSE
        CLOSE #1
    END IF
    qberrorhappened = 0
END IF

reginternal

DIM SHARED GlobTxtBuf: GlobTxtBuf = OpenBuffer%("O", tmpdir$ + "global.txt")
defdatahandle = GlobTxtBuf
WriteBufLine GlobTxtBuf, "template <typename QBL, typename QBR> static inline auto qb_safe_idiv(QBL qb_l,QBR qb_r)->decltype(qb_l/qb_r){if (!qb_r){error(11);return (decltype(qb_l/qb_r))0;}return qb_l/qb_r;}"
WriteBufLine GlobTxtBuf, "template <typename QBL, typename QBR> static inline auto qb_safe_mod(QBL qb_l,QBR qb_r)->decltype(qb_l%qb_r){if (!qb_r){error(11);return (decltype(qb_l%qb_r))0;}return qb_l%qb_r;}"

IF iderecompile THEN
    iderecompile = 0
    idepass = 1 'prepass must be done again
    sendc$ = CHR$(7) 'repass request
    GOTO sendcommand
END IF

IF idemode THEN GOTO ideret1

lineinput3load sourcefile$
GOTO startPrepass

'=== BEGIN: pass dependent GOSUB routines ===
setPrecompFlags:
SetPreLET "_EXPLICIT_", _TOSTR$(GetRCStateVar(OptExpl))
SetPreLET "_EXPLICITARRAY_", _TOSTR$(GetRCStateVar(OptExpl) OR GetRCStateVar(OptExplArr))
SetPreLET "_ASSERTS_", _TOSTR$(GetRCStateVar(AssertsOn))
SetPreLET "_CONSOLE_", _TOSTR$(GetRCStateVar(ConsoleOn))
SetPreLET "_DEBUG_", _TOSTR$(GetRCStateVar(vWatchOn))
'the next exposes the DEPENDENCY_SOCKETS state mainly for use in the
'auto-includes beforefirstline.bi and afterlastline.bm to include/exclude
'network specific code
SetPreLET "_SOCKETS_", _TOSTR$(GetRCStateVar(SockDepOn))
RETURN

autoIncludeManager:
autoIncludeBuffer = OpenBuffer%("O", tmpdir$ + "autoinc.txt")
'following IF blocks must be independent, don't connect them using ELSEIF
IF firstLine = 1 THEN
    IF ideprogname$ <> "beforefirstline.bi" THEN
        WriteBufLine autoIncludeBuffer, "internal\support\include\beforefirstline.bi"
    ELSE
        SetDependency DEPENDENCY_SOCKETS 'force dependency for direct editing
    END IF
    IF GetRCStateVar(ColorSet) = 1 AND ideprogname$ <> "color0.bi" AND ideprogname$ <> "color32.bi" THEN
        WriteBufLine autoIncludeBuffer, "internal\support\color\color0.bi"
    ELSEIF GetRCStateVar(ColorSet) = 2 AND ideprogname$ <> "color0.bi" AND ideprogname$ <> "color32.bi" THEN
        WriteBufLine autoIncludeBuffer, "internal\support\color\color32.bi"
    END IF
    'add "AtTop" files of used libraries
    ullUB = UBOUND(useLibList$, 2)
    FOR i = ullUB TO 0 STEP -1 'in reversed order to pull dependencies before they're needed
        ull$ = useLibList$(ullTop, i)
        IF LEN(ull$) > 0 THEN WriteBufLine autoIncludeBuffer, ull$
    NEXT i
    'add more files in between here
    'add more files in between here
    IF GetRCStateVar(vWatchOn) = 1 OR ideprogname$ = "vwatch.bm" THEN
        IF ideprogname$ <> "vwatch.bi" THEN
            WriteBufLine autoIncludeBuffer, "internal\support\vwatch\vwatch.bi"
        END IF
    END IF
    firstLine = 2 'change state to "in progress"
END IF
IF mainEndLine = 1 THEN
    WriteBufLine autoIncludeBuffer, "internal\support\include\aftermain.bas"
    'add "AfterMain" files of used libraries
    ullUB = UBOUND(useLibList$, 2)
    FOR i = 0 TO ullUB 'in order of appearance
        ull$ = useLibList$(ullMain, i)
        IF LEN(ull$) > 0 THEN WriteBufLine autoIncludeBuffer, ull$
    NEXT i
    'add more files in between here
    'add more files in between here
    mainEndLine = 2 'change state to "in progress"
END IF
IF lastLine = 1 THEN
    'for SUB/FUNC-less main code "AfterMain" and "AtBottom" are triggered at the same time, hence we first
    'need a marker in the buffer to know when "AfterMain" files are done and the "AtBottom" files start
    WriteBufLine autoIncludeBuffer, "-----" 'a simple bar will do that for us (see Include Managers #1/#2)
    IF GetRCStateVar(vWatchOn) THEN
        IF LEFT$(ideprogname$, 6) <> "vwatch" THEN WriteBufLine autoIncludeBuffer, "internal\support\vwatch\vwatch.bm"
    ELSE
        IF LEFT$(ideprogname$, 6) <> "vwatch" THEN WriteBufLine autoIncludeBuffer, "internal\support\vwatch\vwatch_stub.bm"
    END IF
    'add "AtBottom" files of used libraries
    ullUB = UBOUND(useLibList$, 2)
    FOR i = 0 TO ullUB 'in order of appearance
        ull$ = useLibList$(ullBottom, i)
        IF LEN(ull$) > 0 THEN WriteBufLine autoIncludeBuffer, ull$
    NEXT i
    'add more files in between here
    'add more files in between here
    IF ideprogname$ <> "afterlastline.bm" THEN
        WriteBufLine autoIncludeBuffer, "internal\support\include\afterlastline.bm"
    ELSE
        SetDependency DEPENDENCY_SOCKETS 'force dependency for direct editing
    END IF
    lastLine = 2 'change state to "in progress"
END IF
IF GetBufLen&(autoIncludeBuffer) > 0 THEN
    nul& = SeekBuf&(autoIncludeBuffer, 0, SBM_BufStart)
    ON ABS(SGN(prepass)) + 1 GOSUB autoInclude, autoInclude_prepass
END IF
'change states from "in progress" to "done"
IF firstLine = 2 THEN firstLine = 3
IF mainEndLine = 2 THEN mainEndLine = 3
IF lastLine = 2 THEN lastLine = 3
ClearBuffers tmpdir$ + "autoinc.txt": autoIncludeBuffer = -1 'invalidate buffer
RETURN
'=== END: pass dependent GOSUB routines ===

startPrepass:
DO
    ideprepass:
    prepass = 1

    'wholeline$ is passed in idemode, from $include and CLI lastLine trigger
    IF idemode = 0 AND inclevel = 0 AND lastLine = 0 THEN
        wholeline$ = lineinput3$ 'otherwise read from source
        IF wholeline$ = CHR$(13) THEN EXIT DO 'check for end
    END IF
    IF lastLine = 1 AND mainEndLine = 0 THEN mainEndLine = 1
    'perform auto-including according to code position
    IF firstLine = 1 OR (mainEndLine = 1 AND firstLine = 3) OR lastLine = 1 THEN
        lineBackup$ = wholeline$ 'backup the real line
        GOSUB setPrecompFlags
        GOSUB autoIncludeManager
        wholeline$ = lineBackup$
    END IF

    layout = ""
    layoutok = 0

    linenumber = linenumber + 1
    reallinenumber = reallinenumber + 1

    DO UNTIL linenumber < UBOUND(InvalidLine) 'color information flag for each line
        REDIM _PRESERVE InvalidLine(UBOUND(InvalidLine) + 1000) AS _BYTE
    LOOP
    InvalidLine(linenumber) = 0

    IF LEN(wholeline$) THEN

        temp$ = LTRIM$(RTRIM$(UCASE$(wholeline$)))

        IF LEFT$(temp$, 4) = "$IF " THEN
            IF RIGHT$(temp$, 5) <> " THEN" THEN a$ = "$IF without THEN": GOTO errmes
            temp$ = LTRIM$(MID$(temp$, 4)) 'strip off the $IF and extra spaces
            temp$ = RTRIM$(LEFT$(temp$, LEN(temp$) - 4)) 'and strip off the THEN and extra spaces
            temp = INSTR(temp$, "=")
            ExecCounter = ExecCounter + 1
            ExecLevel(ExecCounter) = -1 'default to a skip value
            DefineElse(ExecCounter) = 1 '1 says we have an $IF statement at this level
            result = EvalPreIF(temp$, a$)
            IF a$ <> "" THEN GOTO errmes
            IF result <> 0 THEN
                ExecLevel(ExecCounter) = ExecLevel(ExecCounter - 1) 'So we inherit the execlevel from above
                IF ExecLevel(ExecCounter) = 0 THEN DefineElse(ExecCounter) = DefineElse(ExecCounter) OR 4 'Else if used and condition found
            END IF
            GOTO finishedlinepp 'and then we're finished -- and at this point we didn't make a match so we exit with a DONT READ type flag on our code.
        END IF

        IF temp$ = "$ELSE" THEN
            IF DefineElse(ExecCounter) = 0 THEN a$ = "$ELSE without $IF": GOTO errmes
            IF DefineElse(ExecCounter) AND 2 THEN a$ = "$IF block already has $ELSE statement in it": GOTO errmes
            DefineElse(ExecCounter) = DefineElse(ExecCounter) OR 2 'set the flag to declare an $ELSE already in this block
            IF DefineElse(ExecCounter) AND 4 THEN 'If we executed code in a previous IF or ELSE IF statement, we can't do it here
                ExecLevel(ExecCounter) = -1 'So we inherit the execlevel from above
            ELSE
                ExecLevel(ExecCounter) = ExecLevel(ExecCounter - 1) 'If we were processing code before, code after this segment is going to be SKIPPED
            END IF
            GOTO finishedlinepp
        END IF

        IF LEFT$(temp$, 5) = "$ELSE" THEN 'looking for $ELSE IF
            temp$ = LTRIM$(MID$(temp$, 6))
            IF LEFT$(temp$, 3) = "IF " THEN
                IF DefineElse(ExecCounter) = 0 THEN a$ = "$ELSE IF without $IF": GOTO errmes
                IF DefineElse(ExecCounter) AND 2 THEN a$ = "$ELSE IF cannot follow $ELSE": GOTO errmes
                IF RIGHT$(temp$, 5) <> " THEN" THEN a$ = "$ELSE IF without THEN": GOTO errmes
                IF DefineElse(ExecCounter) AND 4 THEN 'If we executed code in a previous IF or ELSE IF statement, we can't do it here
                    ExecLevel(ExecCounter) = -1
                    GOTO finishedlinepp
                END IF
                temp$ = LTRIM$(MID$(temp$, 3)) 'strip off the IF and extra spaces
                temp$ = RTRIM$(LEFT$(temp$, LEN(temp$) - 4)) 'and strip off the THEN and extra spaces
                result = EvalPreIF(temp$, a$)
                IF a$ <> "" THEN GOTO errmes
                IF result <> 0 THEN
                    ExecLevel(ExecCounter) = ExecLevel(ExecCounter - 1) 'So we inherit the execlevel from above
                    IF ExecLevel(ExecCounter) = 0 THEN DefineElse(ExecCounter) = DefineElse(ExecCounter) OR 4 'Else if used and condition found
                END IF
                GOTO finishedlinepp 'and then we're finished -- and at this point we didn't make a match so we exit with a DONT READ type flag on our code.
            END IF
        END IF

        IF temp$ = "$END IF" OR temp$ = "$ENDIF" THEN
            IF DefineElse(ExecCounter) = 0 THEN a$ = "$END IF without $IF": GOTO errmes
            DefineElse(ExecCounter) = 0 'We no longer have an $IF block at this level
            ExecCounter = ExecCounter - 1
            GOTO finishedlinepp
        END IF

        IF ExecLevel(ExecCounter) THEN
            DO UNTIL linenumber < UBOUND(InvalidLine)
                REDIM _PRESERVE InvalidLine(UBOUND(InvalidLine) + 1000) AS _BYTE
            LOOP

            InvalidLine(linenumber) = -1
            GOTO finishedlinepp 'we don't check for anything inside lines that we've marked for skipping
        END IF

        IF temp$ = "$COLOR:0" THEN
            SetRCStateVar ColorSet, 1
            IF recompile GOTO do_recompile
            GOTO finishedlinepp
        END IF

        IF temp$ = "$COLOR:32" THEN
            SetRCStateVar ColorSet, 2
            IF recompile GOTO do_recompile
            GOTO finishedlinepp
        END IF

        IF LEFT$(temp$, 11) = "$USELIBRARY" THEN
            a$ = "Expected $USELIBRARY:'author/library'"
            'check for lib-spec
            bra = INSTR(temp$, "'"): IF bra = 0 GOTO errmes
            ket = INSTR(bra + 1, temp$, "'"): IF ket = 0 GOTO errmes
            UseLib$ = _TRIM$(MID$(_TRIM$(wholeline$), bra + 1, ket - bra - 1))
            IF LEN(UseLib$) = 0 GOTO errmes
            'verify library existence
            a$ = "Library descriptor for '" + UseLib$ + "' not found"
            UseLibFile$ = "libraries/descriptors/" + UseLib$ + ".ini"
            IF _FILEEXISTS(UseLibFile$) = 0 GOTO errmes
            '-----
            a$ = "Library source for '" + UseLib$ + "' not found ("
            UseLibSrc$ = "libraries/includes/" + UseLib$ + "/": UseLibSect$ = "[LIBRARY INCLUDES]"
            UseLibEntr$ = "IncAtTop": UseLibTop$ = ReadSetting$(UseLibFile$, UseLibSect$, UseLibEntr$)
            IF LEN(UseLibTop$) > 0 THEN
                UseLibTop$ = UseLibSrc$ + UseLibTop$
                IF _FILEEXISTS(UseLibTop$) = 0 THEN a$ = a$ + UseLibEntr$ + ")": GOTO errmes
            END IF
            UseLibEntr$ = "IncAfterMain": UseLibMain$ = ReadSetting$(UseLibFile$, UseLibSect$, UseLibEntr$)
            IF LEN(UseLibMain$) > 0 THEN
                UseLibMain$ = UseLibSrc$ + UseLibMain$
                IF _FILEEXISTS(UseLibMain$) = 0 THEN a$ = a$ + UseLibEntr$ + ")": GOTO errmes
            END IF
            UseLibEntr$ = "IncAtBottom": UseLibBottom$ = ReadSetting$(UseLibFile$, UseLibSect$, UseLibEntr$)
            IF LEN(UseLibBottom$) > 0 THEN
                UseLibBottom$ = UseLibSrc$ + UseLibBottom$
                IF _FILEEXISTS(UseLibBottom$) = 0 THEN a$ = a$ + UseLibEntr$ + ")": GOTO errmes
            END IF
            'who's the referrer (in need of this library)
            IF inclevel = 0 THEN
                IF NoIDEMode THEN
                    UseLibNeedy$ = sourcefile$ + STR$(linenumber)
                ELSE
                    UseLibNeedy$ = ideprogname$ + STR$(linenumber)
                END IF
            ELSE
                UseLibNeedy$ = incname$(inclevel) + STR$(inclinenumber(inclevel))
            END IF
            'avoid duplicate definitions but maintain new dependencies
            ullUB = UBOUND(useLibList$, 2): ullND = -1
            FOR i = 0 TO ullUB
                IF useLibList$(ullName, i) = UseLib$ THEN
                    IF useLibList$(ullNeedy, i) = UseLibNeedy$ THEN ullND = 0
                END IF
            NEXT i
            IF NOT ullND GOTO finishedlinepp
            'register new library (or dependency) for auto-including
            FOR i = 0 TO ullUB
                IF useLibList$(ullName, i) = "" THEN EXIT FOR
            NEXT i
            IF i > ullUB THEN
                REDIM _PRESERVE useLibList$(4, ullUB + 10)
                i = ullUB + 1
            END IF
            useLibList$(ullName, i) = UseLib$
            useLibList$(ullNeedy, i) = UseLibNeedy$
            useLibList$(ullTop, i) = UseLibTop$
            useLibList$(ullMain, i) = UseLibMain$
            useLibList$(ullBottom, i) = UseLibBottom$
            GOTO do_recompile
        END IF

        IF temp$ = "$ASSERTS" THEN
            SetRCStateVar AssertsOn, 1
            SetPreLET "_ASSERTS_", "1"
            GOTO finishedlinepp
        END IF

        IF temp$ = "$ASSERTS:CONSOLE" THEN
            SetRCStateVar AssertsOn, 1
            SetRCStateVar ConsoleOn, 1
            SetPreLET "_ASSERTS_", "1"
            SetPreLET "_CONSOLE_", "1"
            GOTO finishedlinepp
        END IF

        IF temp$ = "$CONSOLE" THEN
            SetRCStateVar ConsoleOn, 1
            SetPreLET "_CONSOLE_", "1"
            GOTO finishedlinepp
        END IF

        IF temp$ = "$CONSOLE:ONLY" THEN
            SetRCStateVar ConsoleOn, 2
            SetPreLET "_CONSOLE_", "2"
            GOTO finishedlinepp
        END IF

        IF temp$ = "$DEBUG" THEN
            SetRCStateVar vWatchOn, 1
            SetPreLET "_DEBUG_", "1"
            GOTO finishedlinepp
        END IF

        IF temp$ = "$ERRORLOCATION:ON" THEN
            SetRCStateVar ErrorLocationMode, 2
            GOTO finishedlinepp
        END IF

        IF temp$ = "$ERRORLOCATION:OFF" THEN
            SetRCStateVar ErrorLocationMode, 1
            GOTO finishedlinepp
        END IF

        IF temp$ = "$NOPREFIX" THEN
            IF idemode THEN
                'Offer to convert the file
                sendc$ = CHR$(13)
                GOTO sendcommand
            ELSE
                a$ = "$NOPREFIX is a deprecated feature, QB64(PE) specific keywords MUST have the underscore. To convert this program, open it in the IDE."
                GOTO errmes
            END IF
        END IF

        IF LEFT$(temp$, 7) = "$ERROR " THEN
            temp$ = RemoveStringEnclosingPair(LTRIM$(MID$(temp$, 7)), METACOMMAND_STRING_ENCLOSING_PAIR)
            a$ = "Compilation check failed: " + temp$
            GOTO errmes
        END IF

        IF LEFT$(temp$, 5) = "$LET " THEN
            temp$ = LTRIM$(MID$(temp$, 5)) 'simply shorten our string to parse
            'For starters, let's make certain that we have 3 elements to deal with
            temp = INSTR(temp$, "=") 'without an = in there, we can't get a value from the left and right side
            IF temp = 0 THEN a$ = "Invalid Syntax.  $LET <flag> = <value>": GOTO errmes
            l$ = RTRIM$(LEFT$(temp$, temp - 1)): r$ = LTRIM$(MID$(temp$, temp + 1))
            'then validate to make certain the left side looks proper
            IF validname(l$) = 0 THEN a$ = "Invalid flag name": GOTO errmes
            IF LEFT$(r$, 1) = CHR$(34) THEN r$ = LTRIM$(MID$(r$, 2))
            IF RIGHT$(r$, 1) = CHR$(34) THEN r$ = RTRIM$(LEFT$(r$, LEN(r$) - 1))
            IF LEFT$(r$, 1) = "-" THEN
                r1$ = "-"
                r$ = LTRIM$(MID$(r$, 2))
            ELSE
                r1$ = ""
            END IF
            'then validate to make certain the left side looks proper
            FOR i = 1 TO LEN(r$)
                a = ASC(r$, i)
                SELECT CASE a
                    CASE 32
                    CASE 46 'periods are fine.
                        r1$ = r1$ + "."
                    CASE IS < 48, IS > 90
                        a$ = "Invalid value": GOTO errmes
                    CASE ELSE
                        r1$ = r1$ + CHR$(a)
                END SELECT
            NEXT
            r$ = r1$
            SetPreLET l$, r$
            GOTO finishedlinepp
        END IF

        ' We check for Unstable flags during the preprocessing step because it
        ' impacts what valid commands there are in all the other steps
        IF LEFT$(temp$, 10) = "$UNSTABLE:" THEN
            token$ = UCASE$(LTRIM$(RTRIM$(MID$(temp$, 11))))

            SELECT CASE token$
                CASE "MIDI"
                    unstableFlags(UNSTABLE_MIDI) = -1

                CASE "HTTP"
                    unstableFlags(UNSTABLE_HTTP) = -1

                CASE "TYPEFIELDS"
                    unstableFlags(UNSTABLE_TYPEFIELDS) = -1

                CASE ELSE
                    a$ = "Unrecognized unstable flag " + AddQuotes$(token$)
                    GOTO errmes
            END SELECT
        END IF

        IF LEFT$(temp$, 15) = "$MIDISOUNDFONT:" THEN
            a$ = "$MIDISOUNDFONT is a deprecated keyword, use _MIDISOUNDBANK instead"
            GOTO errmes
        END IF

        wholeline$ = lineformat(wholeline$)
        IF Error_Happened THEN GOTO errmes

        cwholeline$ = wholeline$
        wholeline$ = eleucase$(wholeline$) '********REMOVE THIS LINE LATER********


        addmetadynamic = 0: addmetastatic = 0
        wholelinen = numelements(wholeline$)

        IF wholelinen THEN

            wholelinei = 1

            'skip line number?
            e$ = getelement$(wholeline$, 1)
            IF (ASC(e$) >= 48 AND ASC(e$) <= 59) OR ASC(e$) = 46 THEN wholelinei = 2: GOTO ppskpl

            'skip 'POSSIBLE' line label?
            IF wholelinen >= 2 THEN
                x2 = INSTR(wholeline$, sp + ":" + sp): x3 = x2 + 2
                IF x2 = 0 THEN
                    IF RIGHT$(wholeline$, 2) = sp + ":" THEN x2 = LEN(wholeline$) - 1: x3 = x2 + 1
                END IF

                IF x2 THEN
                    e$ = LEFT$(wholeline$, x2 - 1)
                    IF validlabel(e$) THEN
                        wholeline$ = RIGHT$(wholeline$, LEN(wholeline$) - x3)
                        cwholeline$ = RIGHT$(cwholeline$, LEN(wholeline$) - x3)
                        wholelinen = numelements(wholeline$)
                        GOTO ppskpl
                    END IF 'valid
                END IF 'includes ":"
            END IF 'wholelinen>=2

            ppskpl:
            IF wholelinei <= wholelinen THEN
                '----------------------------------------
                a$ = ""
                ca$ = ""
                ppblda:
                e$ = getelement$(wholeline$, wholelinei)
                ce$ = getelement$(cwholeline$, wholelinei)
                IF e$ = ":" OR e$ = "ELSE" OR e$ = "THEN" OR e$ = "" THEN
                    IF LEN(a$) THEN
                        IF Debug THEN PRINT #9, "PP[" + a$ + "]"
                        n = numelements(a$)
                        firstelement$ = getelement(a$, 1)
                        secondelement$ = getelement(a$, 2)
                        thirdelement$ = getelement(a$, 3)
                        '========================================

                        IF n = 2 AND firstelement$ = "END" AND (secondelement$ = "SUB" OR secondelement$ = "FUNCTION") THEN
                            subfuncn = 0
                        END IF

                        'declare library
                        IF declaringlibrary THEN

                            IF firstelement$ = "END" THEN
                                IF n <> 2 OR secondelement$ <> "DECLARE" THEN a$ = "Expected END DECLARE": GOTO errmes
                                declaringlibrary = 0
                                GOTO finishedlinepp
                            END IF 'end declare

                            declaringlibrary = 2

                            IF firstelement$ = "SUB" OR firstelement$ = "FUNCTION" THEN GOTO declaresubfunc

                            a$ = "Expected SUB/FUNCTION definition or END DECLARE (#2)": GOTO errmes
                        END IF

                        'Track OPTION BASE during the preprocessing pass.
                        'TYPE member arrays are parsed here before the main compiler pass
                        'updates the global OPTION BASE state, so we must preserve the
                        'source-order value separately for ParseUDTArrayBoundsEx().
                        IF firstelement$ = "OPTION" THEN
                            IF n >= 3 THEN
                                IF secondelement$ = "BASE" THEN
                                    IF thirdelement$ = "0" OR thirdelement$ = "1" THEN
                                        udtparse_optionbase = VAL(thirdelement$)
                                    END IF
                                END IF
                            END IF
                        END IF

                        'UDT TYPE definition
                        IF definingtype THEN
                            i = definingtype

                            IF n >= 1 THEN
                                IF firstelement$ = "END" THEN
                                    IF n <> 2 OR secondelement$ <> "TYPE" THEN a$ = "Expected END TYPE": GOTO errmes
                                    IF udtxnext(i) = 0 THEN a$ = "No elements defined in TYPE": GOTO errmes
                                    definingtype = 0
                                    BuildUDTDynLayout i

                                    'create global buffer for SWAP space
                                    siz$ = _TOSTR$(udtxsize(i) \ 8)
                                    WriteBufLine GlobTxtBuf, "char *g_tmp_udt_" + RTRIM$(udtxname(i)) + "=(char*)malloc(" + siz$ + ");"
                                    GOTO finishedlinepp
                                END IF
                            END IF

                            IF n < 3 THEN a$ = "Expected element-name AS type, AS type element-list, or END TYPE": GOTO errmes
                            n$ = firstelement$

                            IF n$ <> "AS" THEN
                                'traditional variable-name AS type syntax, single-element
                                udtfieldmode = 0
                                udtmembernamepos = 1
                                IF UDTFieldModeToken%(n$) THEN
                                    fieldToken$ = n$
                                    UDTApplyFieldMode fieldToken$, udtfieldmode
                                    IF Error_Happened THEN GOTO errmes
                                    IF n < 4 THEN a$ = "Expected TYPE member array name": GOTO errmes
                                    udtmembernamepos = 2
                                    n$ = getelement$(a$, udtmembernamepos)
                                END IF

                                lasttypeelement = lasttypeelement + 1
                                i2 = lasttypeelement
                                WHILE i2 > UBOUND(udtenext): increaseUDTArrays: WEND
                                udtenext(i2) = 0
                                udtefdynoffset(i2) = 0
                                udtefdynsize(i2) = 0

                                ii = udtmembernamepos + 1

                                ' Initialize TYPE member-array metadata to the non-array state.
                                ' If no (...) declarator is parsed, this TYPE member remains a scalar / non-array field.
                                udtearrayelements(i2) = 0
                                udtearraybase(i2) = 0
                                udtearraydims(i2) = 0
                                udtearraydesc(i2) = ""
                                udtearrayfieldmode(i2) = 0

                                DO WHILE ii <= n
                                    fieldToken$ = getelement$(a$, ii)
                                    IF UDTFieldModeToken%(fieldToken$) = 0 THEN EXIT DO
                                    UDTApplyFieldMode fieldToken$, udtfieldmode
                                    IF Error_Happened THEN GOTO errmes
                                    ii = ii + 1
                                LOOP

                                IF ii < n THEN
                                    IF getelement$(a$, ii) = "(" THEN
                                        b2 = 1
                                        i3 = ii + 1
                                        DO WHILE i3 <= n
                                            l$ = getelement$(a$, i3)
                                            IF l$ = "(" THEN b2 = b2 + 1
                                            IF l$ = ")" THEN
                                                b2 = b2 - 1
                                                IF b2 = 0 THEN EXIT DO
                                            END IF
                                            i3 = i3 + 1
                                        LOOP
                                        IF b2 <> 0 THEN a$ = "Expected )": GOTO errmes

                                        ' Parse compile-time numeric bounds for a TYPE member array.
                                        ' The resulting descriptor is later reused by indexing, LBOUND/UBOUND, ERASE, REDIM and _MEM handling.

                                        IF ParseUDTArrayBoundsEx(getelements$(ca$, ii + 1, i3 - 1), udtparse_optionbase, udtearraybase(i2), udtearrayelements(i2), udtearraydims(i2), udtearraydesc(i2)) = 0 THEN GOTO errmes
                                        ii = i3 + 1
                                    END IF
                                END IF

                                DO WHILE ii <= n
                                    fieldToken$ = getelement$(a$, ii)
                                    IF UDTFieldModeToken%(fieldToken$) = 0 THEN EXIT DO
                                    UDTApplyFieldMode fieldToken$, udtfieldmode
                                    IF Error_Happened THEN GOTO errmes
                                    ii = ii + 1
                                LOOP

                                IF ii >= n OR getelement$(a$, ii) <> "AS" THEN a$ = "Expected element-name AS type, AS type element-list, or END TYPE": GOTO errmes
                                typeLast = n
                                DO WHILE typeLast >= ii + 1
                                    fieldToken$ = getelement$(a$, typeLast)
                                    IF UDTFieldModeToken%(fieldToken$) = 0 THEN EXIT DO
                                    UDTApplyFieldMode fieldToken$, udtfieldmode
                                    IF Error_Happened THEN GOTO errmes
                                    typeLast = typeLast - 1
                                LOOP
                                IF typeLast < ii + 1 THEN a$ = "Expected type": GOTO errmes
                                t$ = getelements$(a$, ii + 1, typeLast)

                                IF t$ = RTRIM$(udtxname(definingtype)) THEN a$ = "Invalid self-reference": GOTO errmes
                                typ = typname2typ(t$)
                                IF Error_Happened THEN GOTO errmes
                                IF typ = 0 THEN a$ = "Undefined type": GOTO errmes
                                typsize = typname2typsize

                                IF validname(n$) = 0 THEN a$ = "Invalid name": GOTO errmes
                                udtename(i2) = n$
                                udtecname(i2) = getelement$(ca$, udtmembernamepos)
                                NormalTypeBlock:
                                ' _Static/_Dynamic are storage-mode markers for member arrays only.
                                ' Reject scalar use here so later layout code never has to interpret a marker
                                ' without array metadata, descriptor bounds, or inline element count.
                                IF udtfieldmode <> 0 AND udtearrayelements(i2) = 0 THEN a$ = "_Dynamic and _Static can only be used on array members inside TYPE": GOTO errmes
                                udtearrayfieldmode(i2) = udtfieldmode
                                typeDefinitions$ = typeDefinitions$ + MKL$(i2) + MKL$(LEN(n$)) + n$
                                udtetype(i2) = typ
                                udtetypesize(i2) = typsize

                                hashname$ = n$

                                'check for name conflicts (any similar reserved or element from current UDT)
                                hashchkflags = HASHFLAG_RESERVED + HASHFLAG_UDTELEMENT
                                hashres = HashFind(hashname$, hashchkflags, hashresflags, hashresref)
                                DO WHILE hashres
                                    IF hashresflags AND HASHFLAG_UDTELEMENT THEN
                                        IF hashresref = i THEN a$ = "Name already in use (" + hashname$ + ")": GOTO errmes
                                    END IF
                                    IF hashresflags AND HASHFLAG_RESERVED THEN
                                        IF hashresflags AND (HASHFLAG_TYPE + HASHFLAG_CUSTOMSYNTAX + HASHFLAG_OPERATOR + HASHFLAG_XELEMENTNAME) THEN a$ = "Name already in use (" + hashname$ + ")": GOTO errmes
                                    END IF
                                    IF hashres <> 1 THEN hashres = HashFindCont(hashresflags, hashresref) ELSE hashres = 0
                                LOOP
                                'add to hash table
                                HashAdd hashname$, HASHFLAG_UDTELEMENT, i

                                'Calculate element's size
                                IF typ AND ISUDT THEN
                                    u = typ AND UDTMASK
                                    udtesize(i2) = udtxsize(u)
                                    IF udtxvariable(u) THEN udtxvariable(i) = -1
                                ELSEIF typ AND ISSTRING THEN
                                    IF (typ AND ISFIXEDLENGTH) = 0 THEN
                                        udtesize(i2) = OFFSETTYPE AND UDTMASK
                                        udtxvariable(i) = -1
                                    ELSE
                                        udtesize(i2) = typsize * 8
                                    END IF
                                ELSEIF typ AND ISOFFSETINBITS THEN
                                    a$ = "Cannot use _BIT inside user defined types": GOTO errmes
                                ELSE
                                    udtesize(i2) = typ AND UDTMASK
                                END IF

                                ' For TYPE member arrays, udtesize() stores the declared inline block size.
                                ' Descriptor-layout sizing is calculated separately in BuildUDTDynLayout().
                                IF udtearrayelements(i2) THEN
                                    udtesize(i2) = udtesize(i2) * udtearrayelements(i2)
                                END IF

                                'Increase block size
                                udtxsize(i) = udtxsize(i) + udtesize(i2)

                                'Link element to previous element
                                IF udtxnext(i) = 0 THEN
                                    udtxnext(i) = i2
                                ELSE
                                    udtenext(i2 - 1) = i2
                                END IF

                                'print "+"+rtrim$(udtename(i2));udtetype(i2);udtesize(i2);udtxsize(i)
                                IF newAsTypeBlockSyntax THEN RETURN
                                GOTO finishedlinepp
                            ELSE
                                'AS-type element-list syntax with per-member _Static/_Dynamic markers
                                'Accepted forms inside TYPE include:
                                '    AS <type> a, b(0 TO 3) _Dynamic, c(1, 2) _Static
                                '    AS <type> _Dynamic b(0 TO 3), _Static c(1, 2)
                                'A second AS token on the same line is invalid.
                                declStart = 0
                                declModeStart = 0
                                FOR i3 = 3 TO n
                                    n$ = getelement$(a$, i3)
                                    IF UDTFieldModeToken%(n$) THEN
                                        IF declModeStart = 0 THEN declModeStart = i3
                                    ELSEIF validname(n$) THEN
                                        IF declModeStart THEN
                                            t$ = getelements$(a$, 2, declModeStart - 1)
                                        ELSE
                                            t$ = getelements$(a$, 2, i3 - 1)
                                        END IF
                                        IF t$ = RTRIM$(udtxname(definingtype)) THEN a$ = "Invalid self-reference": GOTO errmes
                                        typ = typname2typ(t$)
                                        IF Error_Happened THEN GOTO errmes
                                        IF typ THEN
                                            declStart = i3
                                            EXIT FOR
                                        END IF
                                    END IF
                                NEXT
                                IF declStart = 0 THEN a$ = "Expected element-name AS type, AS type element-list, or END TYPE": GOTO errmes
                                typsize = typname2typsize

                                IF declModeStart THEN ii = declModeStart ELSE ii = declStart
                                DO
                                    IF ii > n THEN EXIT DO
                                    udtfieldmode = 0
                                    DO WHILE ii <= n
                                        fieldToken$ = getelement$(a$, ii)
                                        IF UDTFieldModeToken%(fieldToken$) = 0 THEN EXIT DO
                                        UDTApplyFieldMode fieldToken$, udtfieldmode
                                        IF Error_Happened THEN GOTO errmes
                                        ii = ii + 1
                                    LOOP

                                    IF ii > n THEN a$ = "Expected element-name": GOTO errmes
                                    n$ = getelement$(a$, ii)
                                    cn$ = getelement$(ca$, ii)
                                    IF validname(n$) = 0 THEN a$ = "Expected element-name": GOTO errmes

                                    lasttypeelement = lasttypeelement + 1
                                    i2 = lasttypeelement
                                    WHILE i2 > UBOUND(udtenext): increaseUDTArrays: WEND
                                    udtenext(i2) = 0
                                    udtefdynoffset(i2) = 0
                                    udtefdynsize(i2) = 0
                                    udtearrayelements(i2) = 0
                                    udtearraybase(i2) = 0
                                    udtearraydims(i2) = 0
                                    udtearraydesc(i2) = ""
                                    udtearrayfieldmode(i2) = 0

                                    ii = ii + 1
                                    DO WHILE ii <= n
                                        fieldToken$ = getelement$(a$, ii)
                                        IF UDTFieldModeToken%(fieldToken$) = 0 THEN EXIT DO
                                        UDTApplyFieldMode fieldToken$, udtfieldmode
                                        IF Error_Happened THEN GOTO errmes
                                        ii = ii + 1
                                    LOOP

                                    IF ii <= n THEN
                                        IF getelement$(a$, ii) = "(" THEN
                                            b2 = 1
                                            i3 = ii + 1
                                            DO WHILE i3 <= n
                                                l$ = getelement$(a$, i3)
                                                IF l$ = "(" THEN b2 = b2 + 1
                                                IF l$ = ")" THEN
                                                    b2 = b2 - 1
                                                    IF b2 = 0 THEN EXIT DO
                                                END IF
                                                i3 = i3 + 1
                                            LOOP
                                            IF b2 <> 0 THEN a$ = "Expected )": GOTO errmes
                                            IF ParseUDTArrayBoundsEx(getelements$(ca$, ii + 1, i3 - 1), udtparse_optionbase, udtearraybase(i2), udtearrayelements(i2), udtearraydims(i2), udtearraydesc(i2)) = 0 THEN GOTO errmes
                                            ii = i3 + 1
                                        END IF
                                    END IF

                                    DO WHILE ii <= n
                                        fieldToken$ = getelement$(a$, ii)
                                        IF UDTFieldModeToken%(fieldToken$) = 0 THEN EXIT DO
                                        UDTApplyFieldMode fieldToken$, udtfieldmode
                                        IF Error_Happened THEN GOTO errmes
                                        ii = ii + 1
                                    LOOP

                                    IF ii <= n THEN
                                        IF getelement$(a$, ii) = "AS" THEN a$ = "Expected,": GOTO errmes
                                    END IF

                                    udtename(i2) = n$
                                    udtecname(i2) = cn$
                                    IF validname(n$) = 0 THEN a$ = "Invalid name": GOTO errmes

                                    newAsTypeBlockSyntax = -1
                                    GOSUB NormalTypeBlock
                                    newAsTypeBlockSyntax = 0

                                    IF ii > n THEN EXIT DO
                                    IF getelement$(a$, ii) <> "," THEN a$ = "Expected,": GOTO errmes
                                    ii = ii + 1
                                    IF ii > n THEN a$ = "Expected element-name": GOTO errmes
                                LOOP
                                GOTO finishedlinepp
                            END IF
                        END IF 'definingtype

                        IF definingtype AND n >= 1 THEN a$ = "Expected END TYPE": GOTO errmes

                        IF n >= 1 THEN
                            IF firstelement$ = "TYPE" THEN
                                IF n <> 2 THEN a$ = "Expected TYPE typename": GOTO errmes
                                IF lasttype >= UDTMASK THEN a$ = "Too many user-defined types (maximum" + STR$(UDTMASK) + ")": GOTO errmes
                                lasttype = lasttype + 1
                                typeDefinitions$ = typeDefinitions$ + MKL$(-1) + MKL$(lasttype)
                                definingtype = lasttype
                                i = definingtype
                                WHILE i > UBOUND(udtenext): increaseUDTArrays: WEND
                                autoIncForceUScore = 1
                                IF validname(secondelement$) = 0 THEN a$ = "Invalid name": GOTO errmes
                                typeDefinitions$ = typeDefinitions$ + MKL$(LEN(secondelement$)) + secondelement$
                                udtxname(i) = secondelement$
                                udtxcname(i) = getelement(ca$, 2)
                                udtxnext(i) = 0
                                udtxsize(i) = 0
                                udtxfdynsize(i) = 0
                                udtxcanonmode(i) = 0
                                udtxvariable(i) = 0

                                hashname$ = secondelement$
                                hashflags = HASHFLAG_UDT
                                'check for name conflicts (any similar reserved/sub/function/UDT name)
                                hashchkflags = HASHFLAG_RESERVED + HASHFLAG_SUB + HASHFLAG_FUNCTION + HASHFLAG_UDT
                                hashres = HashFind(hashname$, hashchkflags, hashresflags, hashresref)
                                DO WHILE hashres
                                    allow = 0
                                    IF hashresflags AND (HASHFLAG_SUB + HASHFLAG_FUNCTION) THEN
                                        allow = 1
                                    END IF
                                    IF hashresflags AND HASHFLAG_RESERVED THEN
                                        IF (hashresflags AND (HASHFLAG_TYPE + HASHFLAG_OPERATOR + HASHFLAG_CUSTOMSYNTAX + HASHFLAG_XTYPENAME)) = 0 THEN allow = 1
                                    END IF
                                    IF allow = 0 THEN a$ = "Name already in use (" + hashname$ + ")": GOTO errmes
                                    IF hashres <> 1 THEN hashres = HashFindCont(hashresflags, hashresref) ELSE hashres = 0
                                LOOP

                                'add to hash table
                                HashAdd hashname$, hashflags, i

                                GOTO finishedlinepp
                            END IF
                        END IF





                        IF n >= 1 AND firstelement$ = "CONST" THEN
                            'l$ = "CONST"
                            'DEF... do not change type, the expression is stored in a suitable type
                            'based on its value if type isn't forced/specified

                            'convert periods to _046_
                            i2 = INSTR(a$, sp + "." + sp)
                            IF i2 THEN
                                DO
                                    a$ = LEFT$(a$, i2 - 1) + fix046$ + RIGHT$(a$, LEN(a$) - i2 - 2)
                                    ca$ = LEFT$(ca$, i2 - 1) + fix046$ + RIGHT$(ca$, LEN(ca$) - i2 - 2)
                                    i2 = INSTR(a$, sp + "." + sp)
                                LOOP UNTIL i2 = 0
                                n = numelements(a$)
                                firstelement$ = getelement(a$, 1): secondelement$ = getelement(a$, 2): thirdelement$ = getelement(a$, 3)
                            END IF

                            IF n < 3 THEN a$ = "Expected CONST name = value/expression": GOTO errmes
                            i = 2
                            constdefpendingpp:
                            pending = 0

                            n$ = getelement$(ca$, i): i = i + 1
                            typeoverride = 0
                            s$ = removesymbol$(n$)
                            IF Error_Happened THEN GOTO errmes
                            IF s$ <> "" THEN
                                typeoverride = typname2typ(s$)
                                IF Error_Happened THEN GOTO errmes
                                IF typeoverride AND ISFIXEDLENGTH THEN a$ = "Invalid constant type": GOTO errmes
                                IF typeoverride = 0 THEN a$ = "Invalid constant type": GOTO errmes
                            END IF

                            IF getelement$(a$, i) <> "=" THEN a$ = "Expected =": GOTO errmes
                            i = i + 1

                            'get expression
                            e$ = ""
                            B = 0
                            FOR i2 = i TO n
                                e2$ = getelement$(ca$, i2)
                                IF e2$ = "(" THEN B = B + 1
                                IF e2$ = ")" THEN B = B - 1
                                IF e2$ = "," AND B = 0 THEN
                                    pending = 1
                                    i = i2 + 1
                                    IF i > n - 2 THEN a$ = "Expected CONST ... , name = value/expression": GOTO errmes
                                    EXIT FOR
                                END IF

                                IF LEN(e$) = 0 THEN e$ = e2$ ELSE e$ = e$ + sp + e2$
                            NEXT

                            'intercept current expression and pass it through Evaluate_Expression$
                            '(unless it is a literal string)
                            DIM tempNum AS ParseNum
                            temp1$ = _TRIM$(Evaluate_Expression$(e$, tempNum))

                            IF LEFT$(temp1$, 8) = "ERROR - " THEN
                                a$ = MID$(temp1$, 9)
                                GOTO errmes
                            END IF

                            t = tempNum.typ
                            IF t AND ISSTRING THEN
                                IF typeoverride THEN
                                    IF (typeoverride AND ISSTRING) = 0 THEN a$ = "Type mismatch": GOTO errmes
                                END IF

                                e$ = temp1$
                            ELSE
                                IF typeoverride THEN
                                    IF typeoverride AND ISSTRING THEN a$ = "Type mismatch": GOTO errmes
                                END IF

                                IF t AND ISFLOAT THEN
                                    constval## = tempNum.f
                                    constval&& = constval##
                                    constval~&& = constval&&
                                ELSE
                                    IF (t AND ISUNSIGNED) AND (t AND UDTMASK) = 64 THEN
                                        constval~&& = tempNum.ui
                                        constval&& = constval~&&
                                        constval## = constval&&
                                    ELSE
                                        constval&& = tempNum.i
                                        constval## = constval&&
                                        constval~&& = constval&&
                                    END IF
                                END IF

                                'override type?
                                IF typeoverride THEN
                                    'range check required here (noted in todo)
                                    t = typeoverride
                                END IF
                            END IF

                            constlast = constlast + 1
                            IF constlast > constmax THEN
                                constmax = constmax * 2
                                REDIM _PRESERVE constname(constmax) AS STRING
                                REDIM _PRESERVE constcname(constmax) AS STRING
                                REDIM _PRESERVE constnamesymbol(constmax) AS STRING 'optional name symbol
                                REDIM _PRESERVE consttype(constmax) AS LONG 'variable type number
                                REDIM _PRESERVE constinteger(constmax) AS _INTEGER64
                                REDIM _PRESERVE constuinteger(constmax) AS _UNSIGNED _INTEGER64
                                REDIM _PRESERVE constfloat(constmax) AS _FLOAT
                                REDIM _PRESERVE conststring(constmax) AS STRING
                                REDIM _PRESERVE constsubfunc(constmax) AS LONG
                                REDIM _PRESERVE constdefined(constmax) AS LONG
                            END IF

                            i2 = constlast

                            constsubfunc(i2) = subfuncn

                            autoIncForceUScore = 1
                            IF validname(n$) = 0 THEN a$ = "Invalid name": GOTO errmes
                            constname(i2) = UCASE$(n$)

                            hashname$ = n$
                            'check for name conflicts (any similar: reserved, sub, function, constant)

                            allow = 0
                            const_recheck:
                            hashchkflags = HASHFLAG_RESERVED + HASHFLAG_SUB + HASHFLAG_FUNCTION + HASHFLAG_CONSTANT
                            hashres = HashFind(hashname$, hashchkflags, hashresflags, hashresref)
                            DO WHILE hashres
                                IF hashresflags AND HASHFLAG_CONSTANT THEN
                                    IF constsubfunc(hashresref) = subfuncn THEN
                                        'If merely redefining a CONST with same value
                                        'just issue a warning instead of an error
                                        issueWarning = _FALSE
                                        IF t AND ISSTRING THEN
                                            IF conststring(hashresref) = e$ THEN issueWarning = _TRUE: thisconstval$ = e$
                                        ELSE
                                            IF t AND ISFLOAT THEN
                                                IF constfloat(hashresref) = constval## THEN issueWarning = _TRUE: thisconstval$ = _TOSTR$(constval##)
                                            ELSE
                                                IF t AND ISUNSIGNED THEN
                                                    IF constuinteger(hashresref) = constval~&& THEN issueWarning = _TRUE: thisconstval$ = _TOSTR$(constval~&&)
                                                ELSE
                                                    IF constinteger(hashresref) = constval&& THEN issueWarning = _TRUE: thisconstval$ = _TOSTR$(constval&&)
                                                END IF
                                            END IF
                                        END IF
                                        IF issueWarning THEN
                                            IF NOT IgnoreWarnings THEN
                                                addWarning linenumber, inclevel, inclinenumber(inclevel), incname$(inclevel), "Duplicate constant definition", n$ + " = " + thisconstval$
                                            END IF
                                            GOTO constAddDone
                                        ELSE
                                            a$ = "Name already in use (" + hashname$ + ")": GOTO errmes
                                        END IF
                                    END IF
                                END IF
                                IF hashresflags AND HASHFLAG_RESERVED THEN
                                    a$ = "Name already in use (" + hashname$ + ")": GOTO errmes
                                END IF
                                IF hashresflags AND (HASHFLAG_SUB + HASHFLAG_FUNCTION) THEN
                                    IF ids(hashresref).internal_subfunc = 0 OR RTRIM$(ids(hashresref).musthave) <> "$" THEN a$ = "Name already in use (" + hashname$ + ")": GOTO errmes
                                    IF t AND ISSTRING THEN a$ = "Name already in use (" + hashname$ + ")": GOTO errmes
                                END IF
                                IF hashres <> 1 THEN hashres = HashFindCont(hashresflags, hashresref) ELSE hashres = 0
                            LOOP

                            'add to hash table
                            HashAdd hashname$, HASHFLAG_CONSTANT, i2





                            constdefined(i2) = 1
                            constcname(i2) = n$
                            constnamesymbol(i2) = typevalue2symbol$(t)
                            IF Error_Happened THEN GOTO errmes
                            consttype(i2) = t
                            IF t AND ISSTRING THEN
                                conststring(i2) = e$
                            ELSE
                                IF t AND ISFLOAT THEN
                                    constfloat(i2) = constval##
                                ELSE
                                    IF t AND ISUNSIGNED THEN
                                        constuinteger(i2) = constval~&&
                                    ELSE
                                        constinteger(i2) = constval&&
                                    END IF
                                END IF
                            END IF

                            constAddDone:

                            IF pending THEN
                                'l$ = l$ + sp2 + ","
                                GOTO constdefpendingpp
                            END IF

                            'layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                            GOTO finishedlinepp
                        END IF



                        'DEFINE
                        d = 0
                        IF firstelement$ = "DEFINT" THEN d = 1
                        IF firstelement$ = "DEFLNG" THEN d = 1
                        IF firstelement$ = "DEFSNG" THEN d = 1
                        IF firstelement$ = "DEFDBL" THEN d = 1
                        IF firstelement$ = "DEFSTR" THEN d = 1
                        IF firstelement$ = "_DEFINE" THEN d = 1
                        IF d THEN
                            predefining = 1: GOTO predefine
                            predefined: predefining = 0
                            GOTO finishedlinepp
                        END IF

                        'declare library
                        IF firstelement$ = "DECLARE" THEN
                            IF secondelement$ = "LIBRARY" OR secondelement$ = "DYNAMIC" OR secondelement$ = "CUSTOMTYPE" OR secondelement$ = "STATIC" THEN
                                declaringlibrary = 1
                                indirectlibrary = 0
                                IF secondelement$ = "CUSTOMTYPE" OR secondelement$ = "DYNAMIC" THEN indirectlibrary = 1
                                GOTO finishedlinepp
                            END IF
                        END IF

                        'SUB/FUNCTION
                        dynamiclibrary = 0
                        declaresubfunc:
                        firstelement$ = getelement$(a$, 1)
                        sf = 0
                        IF firstelement$ = "FUNCTION" THEN sf = 1
                        IF firstelement$ = "SUB" THEN sf = 2
                        IF sf THEN

                            IF declaringlibrary = 0 THEN
                                subfuncnlast = subfuncnlast + 1
                                subfuncn = subfuncnlast
                            END IF

                            IF n = 1 THEN a$ = "Expected name after SUB/FUNCTION": GOTO errmes

                            'convert periods to _046_
                            i2 = INSTR(a$, sp + "." + sp)
                            IF i2 THEN
                                DO
                                    a$ = LEFT$(a$, i2 - 1) + fix046$ + RIGHT$(a$, LEN(a$) - i2 - 2)
                                    ca$ = LEFT$(ca$, i2 - 1) + fix046$ + RIGHT$(ca$, LEN(ca$) - i2 - 2)
                                    i2 = INSTR(a$, sp + "." + sp)
                                LOOP UNTIL i2 = 0
                                n = numelements(a$)
                                firstelement$ = getelement(a$, 1): secondelement$ = getelement(a$, 2): thirdelement$ = getelement(a$, 3)
                            END IF

                            n$ = getelement$(ca$, 2)
                            symbol$ = removesymbol$(n$)
                            IF Error_Happened THEN GOTO errmes
                            IF sf = 2 AND symbol$ <> "" THEN a$ = "Type symbols after a SUB name are invalid": GOTO errmes

                            'remove STATIC (which is ignored)
                            e$ = getelement$(a$, n): IF e$ = "STATIC" THEN a$ = LEFT$(a$, LEN(a$) - 7): ca$ = LEFT$(ca$, LEN(ca$) - 7): n = n - 1

                            'check for ALIAS
                            aliasname$ = n$ 'use given name by default
                            IF n > 2 THEN
                                e$ = getelement$(a$, 3)
                                IF e$ = "ALIAS" THEN
                                    IF declaringlibrary = 0 THEN a$ = "ALIAS can only be used with DECLARE LIBRARY": GOTO errmes
                                    IF n = 3 THEN a$ = "Expected ALIAS name-in-library": GOTO errmes
                                    e$ = getelement$(ca$, 4)
                                    'strip string content (optional)
                                    IF LEFT$(e$, 1) = CHR$(34) THEN
                                        e$ = RIGHT$(e$, LEN(e$) - 1)
                                        x = INSTR(e$, CHR$(34)): IF x = 0 THEN a$ = "Expected " + CHR$(34): GOTO errmes
                                        e$ = LEFT$(e$, x - 1)
                                    END IF
                                    'strip fix046$ (created by unquoted periods)
                                    DO WHILE INSTR(e$, fix046$)
                                        x = INSTR(e$, fix046$): e$ = LEFT$(e$, x - 1) + "." + RIGHT$(e$, LEN(e$) - x + 1 - LEN(fix046$))
                                    LOOP
                                    'validate alias name
                                    IF LEN(e$) = 0 THEN a$ = "Expected ALIAS name-in-library": GOTO errmes
                                    FOR x = 1 TO LEN(e$)
                                        a = ASC(e$, x)
                                        IF alphanumeric(a) = 0 _ANDALSO INSTR(" !%&()*+,-./:;<=>?[]^{|}~", CHR$(a)) = 0 THEN
                                            a$ = "Expected ALIAS name-in-library": GOTO errmes
                                        END IF
                                    NEXT
                                    aliasname$ = e$
                                    'remove ALIAS section from line
                                    IF n <= 4 THEN a$ = getelements(a$, 1, 2)
                                    IF n >= 5 THEN a$ = getelements(a$, 1, 2) + sp + getelements(a$, 5, n)
                                    IF n <= 4 THEN ca$ = getelements(ca$, 1, 2)
                                    IF n >= 5 THEN ca$ = getelements(ca$, 1, 2) + sp + getelements(ca$, 5, n)
                                    n = n - 2
                                END IF
                            END IF

                            IF declaringlibrary THEN
                                IF indirectlibrary THEN
                                    aliasname$ = n$ 'override the alias name
                                END IF
                            END IF

                            params = 0
                            params$ = ""
                            paramsize$ = ""
                            nele$ = ""
                            nelereq$ = ""
                            dynudtargmode$ = ""
                            IF n > 2 THEN
                                e$ = getelement$(a$, 3)
                                IF e$ <> "(" THEN a$ = "Expected (": GOTO errmes
                                e$ = getelement$(a$, n)
                                IF e$ <> ")" THEN a$ = "Expected )": GOTO errmes
                                IF n < 4 THEN a$ = "Expected ( ... )": GOTO errmes
                                IF n = 4 THEN GOTO nosfparams
                                B = 0
                                a2$ = ""
                                FOR i = 4 TO n - 1
                                    e$ = getelement$(a$, i)
                                    IF e$ = "(" THEN B = B + 1
                                    IF e$ = ")" THEN B = B - 1
                                    IF e$ = "," AND B = 0 THEN
                                        IF i = n - 1 THEN a$ = "Expected , ... )": GOTO errmes
                                        getlastparam:
                                        IF a2$ = "" THEN a$ = "Expected ... ,": GOTO errmes
                                        a2$ = LEFT$(a2$, LEN(a2$) - 1)
                                        'possible format: [BYVAL]a[%][(1)][AS][type]
                                        n2 = numelements(a2$)
                                        array = 0
                                        t2$ = ""

                                        i2 = 1
                                        e$ = getelement$(a2$, i2): i2 = i2 + 1

                                        byvalue = 0
                                        IF e$ = "BYVAL" THEN
                                            IF declaringlibrary = 0 THEN a$ = "BYVAL can currently only be used with DECLARE LIBRARY": GOTO errmes
                                            e$ = getelement$(a2$, i2): i2 = i2 + 1: byvalue = 1
                                        END IF

                                        n2$ = e$
                                        symbol2$ = removesymbol$(n2$)
                                        IF validname(n2$) = 0 THEN a$ = "Invalid name": GOTO errmes

                                        IF Error_Happened THEN GOTO errmes
                                        m = 0
                                        FOR i2 = i2 TO n2
                                            e$ = getelement$(a2$, i2)
                                            IF e$ = "(" THEN
                                                IF m <> 0 THEN a$ = "Syntax error - too many opening brackets": GOTO errmes
                                                m = 1
                                                array = 1
                                                GOTO gotaa
                                            END IF
                                            IF e$ = ")" THEN
                                                IF m <> 1 THEN a$ = "Syntax error - closing bracket without opening bracket": GOTO errmes
                                                m = 2
                                                GOTO gotaa
                                            END IF
                                            IF e$ = "AS" THEN
                                                IF m <> 0 AND m <> 2 THEN a$ = "Syntax error - check your brackets": GOTO errmes
                                                m = 3
                                                GOTO gotaa
                                            END IF
                                            IF m = 1 THEN
                                                IF declaringlibrary = 0 THEN a$ = "Array parameters require empty parentheses ()": GOTO errmes
                                                GOTO gotaa 'DECLARE LIBRARY keeps its legacy bracket contents
                                            END IF
                                            IF m <> 3 THEN a$ = "Syntax error - check your brackets": GOTO errmes
                                            IF t2$ = "" THEN t2$ = e$ ELSE t2$ = t2$ + " " + e$
                                            gotaa:
                                        NEXT i2

                                        params = params + 1: IF params > 100 THEN a$ = "SUB/FUNCTION exceeds 100 parameter limit": GOTO errmes

                                        argnelereq = 0
                                        argdynmode = 0

                                        IF symbol2$ <> "" AND t2$ <> "" THEN a$ = "Syntax error - check parameter types": GOTO errmes
                                        IF t2$ = "" AND e$ = "AS" THEN a$ = "Expected AS type": GOTO errmes
                                        IF t2$ = "" THEN t2$ = symbol2$
                                        IF t2$ = "" THEN
                                            IF LEFT$(n2$, 1) = "_" THEN v = 27 ELSE v = ASC(UCASE$(n2$)) - 64
                                            t2$ = defineaz(v)
                                        END IF

                                        paramsize = 0
                                        IF array = 1 THEN
                                            t = typname2typ(t2$)
                                            IF Error_Happened THEN GOTO errmes
                                            IF t = 0 THEN a$ = "Illegal SUB/FUNCTION parameter": GOTO errmes
                                            IF (t AND ISFIXEDLENGTH) THEN paramsize = typname2typsize
                                            IF t AND ISUDT THEN argdynmode = GetUDTCanonMode&(t AND UDTMASK)
                                            t = t + ISARRAY
                                            'The existing recompile list is retained only for resolving
                                            'an unknown number of ordinary array dimensions. UDT layout
                                            'mode is canonical and never comes from this list.
                                            FOR i10 = 0 TO sflistn
                                                IF sfidlist(i10) = idn + 1 THEN
                                                    IF sfarglist(i10) = params THEN argnelereq = sfelelist(i10)
                                                END IF
                                            NEXT
                                        ELSE
                                            t = typname2typ(t2$)
                                            IF Error_Happened THEN GOTO errmes
                                            IF t = 0 THEN a$ = "Illegal SUB/FUNCTION parameter": GOTO errmes
                                            IF (t AND ISFIXEDLENGTH) THEN paramsize = typname2typsize

                                            IF t AND ISUDT THEN argdynmode = GetUDTCanonMode&(t AND UDTMASK)

                                            IF byvalue THEN
                                                IF t AND ISPOINTER THEN t = t - ISPOINTER
                                            END IF

                                        END IF
                                        nelereq$ = nelereq$ + CHR$(argnelereq)
                                        dynudtargmode$ = dynudtargmode$ + CHR$(argdynmode)

                                        'consider changing 0 in following line too!
                                        nele$ = nele$ + CHR$(0)

                                        paramsize$ = paramsize$ + MKL$(paramsize)
                                        params$ = params$ + MKL$(t)
                                        a2$ = ""
                                    ELSE
                                        a2$ = a2$ + e$ + sp
                                        IF i = n - 1 THEN GOTO getlastparam
                                    END IF
                                NEXT i
                            END IF 'n>2
                            nosfparams:

                            IF sf = 1 THEN
                                'function
                                clearid
                                id.n = n$
                                id.subfunc = 1

                                id.callname = "FUNC_" + UCASE$(n$)
                                IF declaringlibrary THEN
                                    id.ccall = 1
                                    IF indirectlibrary = 0 THEN id.callname = aliasname$
                                END IF
                                id.args = params
                                id.arg = params$
                                id.argsize = paramsize$
                                id.nele = nele$
                                id.nelereq = nelereq$
                                id.dynudtargmode = dynudtargmode$
                                IF symbol$ <> "" THEN
                                    id.ret = typname2typ(symbol$)
                                    IF Error_Happened THEN GOTO errmes
                                ELSE
                                    IF LEFT$(n$, 1) = "_" THEN v = 27 ELSE v = ASC(UCASE$(n$)) - 64
                                    symbol$ = defineaz(v)
                                    id.ret = typname2typ(symbol$)
                                    IF Error_Happened THEN GOTO errmes
                                END IF
                                IF id.ret = 0 THEN a$ = "Invalid FUNCTION return type": GOTO errmes

                                IF declaringlibrary THEN

                                    ctype$ = typ2ctyp$(id.ret, "")
                                    IF Error_Happened THEN GOTO errmes
                                    IF ctype$ = "qbs" THEN ctype$ = "char*"
                                    id.callname = "(  " + ctype$ + "  )" + RTRIM$(id.callname)

                                END IF

                                s$ = LEFT$(symbol$, 1)
                                IF s$ <> "~" AND s$ <> "`" AND s$ <> "%" AND s$ <> "&" AND s$ <> "!" AND s$ <> "#" AND s$ <> "$" THEN
                                    symbol$ = type2symbol$(symbol$)
                                    IF Error_Happened THEN GOTO errmes
                                END IF
                                id.mayhave = symbol$
                                IF id.ret AND ISPOINTER THEN
                                    IF (id.ret AND ISSTRING) = 0 THEN id.ret = id.ret - ISPOINTER
                                END IF

                                IF declaringlibrary = 0 THEN
                                    pwl$ = StrReplace$(cwholeline$, CHR$(13), " "): pwl$ = StrReplace$(pwl$, "( ", "(")
                                    pwl$ = StrReplace$(pwl$, " ,", ","): pwl$ = StrReplace$(pwl$, " )", ")")
                                    pwl$ = MID$(pwl$, INSTR(UCASE$(pwl$), "FUNCTION") + 9 + LEN(n$))
                                    pwl$ = LTRIM$(MID$(pwl$, INSTR(pwl$, " ")))
                                    apo% = INSTR(UCASE$(pwl$), "STATIC")
                                    IF apo% = 0 THEN apo% = INSTR(pwl$, "'")
                                    IF apo% = 0 THEN apo% = LEN(pwl$) + 1
                                    cpo% = _INSTRREV(apo%, pwl$, ")")
                                    pwl$ = n$ + symbol$ + StrReplace$(RTRIM$(LEFT$(pwl$, cpo%)), "_", "")
                                    pwl$ = StrReplace$(pwl$, " ()", "()")
                                    id.hr_syntax = pwl$
                                END IF

                                IF UCASE$(LEFT$(n$, 5)) = "_IKW_" THEN
                                    reginternalsubfunc = 1: id.n = MID$(n$, 5): id.callname = "FUNC_" + UCASE$(MID$(n$, 5))
                                    id.hr_syntax = UCASE$(MID$(n$, 5)) + _IIF(symbol$ = "$", "$", "") + MID$(id.hr_syntax, LEN(n$) + LEN(symbol$) + 1)
                                END IF
                                regid
                                reginternalsubfunc = 0

                                IF Error_Happened THEN GOTO errmes
                            ELSE
                                'sub
                                clearid
                                id.n = n$
                                id.subfunc = 2
                                id.callname = "SUB_" + UCASE$(n$)
                                IF declaringlibrary THEN
                                    id.ccall = 1
                                    IF indirectlibrary = 0 THEN id.callname = aliasname$
                                END IF
                                id.args = params
                                id.arg = params$
                                id.argsize = paramsize$
                                id.nele = nele$
                                id.nelereq = nelereq$
                                id.dynudtargmode = dynudtargmode$

                                IF declaringlibrary = 0 THEN
                                    pwl$ = StrReplace$(cwholeline$, CHR$(13), " "): pwl$ = StrReplace$(pwl$, "( ", "(")
                                    pwl$ = StrReplace$(pwl$, " ,", ","): pwl$ = StrReplace$(pwl$, " )", ")")
                                    pwl$ = MID$(pwl$, INSTR(UCASE$(pwl$), "SUB") + 4 + LEN(n$))
                                    pwl$ = LTRIM$(MID$(pwl$, INSTR(pwl$, " ")))
                                    apo% = INSTR(UCASE$(pwl$), "STATIC")
                                    IF apo% = 0 THEN apo% = INSTR(pwl$, "'")
                                    IF apo% = 0 THEN apo% = LEN(pwl$) + 1
                                    cpo% = _INSTRREV(apo%, pwl$, ")")
                                    pwl$ = n$ + " " + StrReplace$(RTRIM$(MID$(pwl$, 2, cpo% - 2)), "_", "")
                                    pwl$ = StrReplace$(pwl$, " ()", "()")
                                    id.hr_syntax = pwl$
                                END IF

                                IF UCASE$(LEFT$(n$, 5)) = "_IKW_" THEN reginternalsubfunc = 1: id.n = MID$(n$, 5): id.callname = "SUB_" + UCASE$(MID$(n$, 5)): id.hr_syntax = UCASE$(MID$(n$, 5)) + MID$(id.hr_syntax, LEN(n$) + 1)
                                IF UCASE$(n$) = "_GL" AND params = 0 AND UseGL = 0 THEN reginternalsubfunc = 1: UseGL = 1: id.n = "_GL": SetDependency DEPENDENCY_GL
                                regid
                                reginternalsubfunc = 0

                                IF Error_Happened THEN GOTO errmes
                            END IF


                        END IF

                        '========================================
                        finishedlinepp:
                    END IF
                    a$ = ""
                    ca$ = ""
                ELSE
                    IF a$ = "" THEN a$ = e$: ca$ = ce$ ELSE a$ = a$ + sp + e$: ca$ = ca$ + sp + ce$
                END IF
                IF wholelinei <= wholelinen THEN wholelinei = wholelinei + 1: GOTO ppblda
                '----------------------------------------
            END IF 'wholelinei<=wholelinen
        END IF 'wholelinen
    END IF 'len(wholeline$)

    'Include Manager #1



    IF LEN(addmetainclude$) THEN
        IF Debug THEN PRINT #9, "Pre-pass:INCLUDE$-ing file:'" + addmetainclude$ + "':On line"; linenumber
        a$ = addmetainclude$: addmetainclude$ = "" 'read/clear message

        IF inclevel = 0 THEN
            includingFromRoot = 0
            autoIncludingFile = 0
            autoInclude_prepass:
            IF autoIncludeBuffer <> -1 THEN
                a$ = ReadBufLine$(autoIncludeBuffer)
                IF a$ = "-----" THEN mainEndLine = 3: GOTO autoInclude_prepass '"AfterMain" is done
                autoIncludingFile = 1
                IF RIGHT$(a$, 18) = "beforefirstline.bi" OR RIGHT$(a$, 16) = "afterlastline.bm" THEN
                    autoIncludingFile = -1
                END IF
                includingFromRoot = 1
            END IF
        END IF

        IF inclevel = 100 THEN
            FOR fh = 200 TO 299: CLOSE #fh: NEXT fh 'close all includes
            a$ = "Too many indwelling INCLUDE files": GOTO errmes
        END IF
        '1. Verify file exists (location is either (a)relative to source file or (b)absolute)
        IF LEFT$(a$, 2) = ".\" OR LEFT$(a$, 2) = "./" THEN a$ = MID$(a$, 3)
        fh = 199 + inclevel + 1

        firstTryMethod = 1
        IF includingFromRoot <> 0 AND inclevel = 0 THEN firstTryMethod = 2
        FOR try = firstTryMethod TO 2 'if including file from root, do not attempt including from relative location
            IF try = 1 THEN
                IF inclevel = 0 THEN
                    IF idemode THEN p$ = idepath$ + pathsep$ ELSE p$ = getfilepath$(sourcefile$)
                ELSE
                    p$ = getfilepath$(incname$(inclevel))
                END IF
                f$ = p$ + a$
            END IF
            IF try = 2 THEN f$ = a$
            IF _FILEEXISTS(f$) THEN
                qberrorhappened = -3 '***
                OPEN f$ FOR BINARY AS #fh
                qberrorhappened3: '***
                IF qberrorhappened = -3 THEN
                    '=== BEGIN: handling $INCLUDEONCE ===
                    incDAT$ = SPACE$(LOF(fh))
                    GET #fh, , incDAT$
                    CLOSE #fh 'as we skip the regular CLOSE when $INCLUDEONCE
                    incDAT$ = UCASE$(incDAT$)
                    incPOS& = INSTR(incDAT$, "$INCLUDEONCE" + MKI$(&H0A0D))
                    IF incPOS& = 0 OR incPOS& > 1 THEN
                        IF incPOS& = 0 THEN incPOS& = INSTR(incDAT$, "$INCLUDEONCE" + CHR$(10))
                        IF incPOS& = 0 OR incPOS& > 1 THEN
                            incPOS& = INSTR(incDAT$, CHR$(10) + "$INCLUDEONCE" + MKI$(&H0A0D))
                            IF incPOS& = 0 THEN incPOS& = INSTR(incDAT$, CHR$(10) + "$INCLUDEONCE" + CHR$(10))
                        END IF
                    END IF
                    IF incPOS& > 0 THEN
                        nul& = SeekBuf&(IncOneBuf, 0, SBM_BufStart)
                        WHILE NOT EndOfBuf%(IncOneBuf)
                            IF _FULLPATH$(f$) = ReadBufLine$(IncOneBuf) THEN
                                qberrorhappened = 0
                                GOTO skipInc1
                            END IF
                        WEND
                    END IF
                    WriteBufLine IncOneBuf, _FULLPATH$(f$)
                    OPEN f$ FOR BINARY AS #fh 'reopen and continue
                    '=== END: handling $INCLUDEONCE ===
                    EXIT FOR '***
                END IF
            END IF
            qberrorhappened = 0
        NEXT
        IF qberrorhappened <> -3 THEN qberrorhappened = 0: a$ = "File " + a$ + " not found": GOTO errmes
        qberrorhappened = 0
        inclevel = inclevel + 1: incname$(inclevel) = f$: inclinenumber(inclevel) = 0
    END IF 'fall through to next section...
    '--------------------
    DO WHILE inclevel

        fh = 199 + inclevel
        '2. Feed next line
        IF EOF(fh) = 0 THEN
            LINE INPUT #fh, x$

            wholeline$ = x$
            inclinenumber(inclevel) = inclinenumber(inclevel) + 1
            'create extended error string 'incerror$'
            errorLineInInclude = inclinenumber(inclevel)
            e$ = " in line " + _TOSTR$(inclinenumber(inclevel)) + " of " + incname$(inclevel)
            IF autoIncludingFile <> 0 THEN e$ = e$ + " auto-included" ELSE e$ = e$ + " included"
            IF inclevel > 1 THEN
                e$ = e$ + " (through "
                FOR x = 1 TO inclevel - 1 STEP 1
                    e$ = e$ + incname$(x)
                    IF x < inclevel - 1 THEN 'a sep is req
                        IF x = inclevel - 2 THEN
                            e$ = e$ + " then "
                        ELSE
                            e$ = e$ + ", "
                        END IF
                    END IF
                NEXT
                e$ = e$ + ")"
            END IF
            incerror$ = e$
            linenumber = linenumber - 1 'lower official linenumber to counter later increment

            IF Debug THEN PRINT #9, "Pre-pass:Feeding INCLUDE$ line:[" + wholeline$ + "]"

            IF idemode THEN sendc$ = CHR$(10) + wholeline$: GOTO sendcommand 'passback
            GOTO ideprepass
        END IF
        '3. Close & return control
        CLOSE #fh
        inclevel = inclevel - 1
        skipInc1:
        IF autoIncludingFile <> 0 AND (inclevel = 0 OR mainEndLine = 2) THEN
            IF NOT EndOfBuf%(autoIncludeBuffer) GOTO autoInclude_prepass
            autoIncludingFile = 0
            RETURN 'to auto-include manager
        END IF
    LOOP
    '(end manager)

    IF idemode THEN GOTO ideret2
    IF lastLineReturn = 1 THEN EXIT DO
LOOP

'add final line
IF lastLineReturn = 0 THEN
    lastLineReturn = 1
    lastLine = 1
    wholeline$ = ""
    GOTO ideprepass
END IF

IF definingtype THEN definingtype = 0 'ignore this error so that auto-formatting can be performed and catch it again later
IF declaringlibrary THEN declaringlibrary = 0 'ignore this error so that auto-formatting can be performed and catch it again later

totallinenumber = reallinenumber

'prepass finished

lineinput3index = 1 'reset input line

'ide specific
ide3:

addmetainclude$ = "" 'reset stray meta-includes
IncOneBuf = OpenBuffer%("O", tmpdir$ + "incone.txt") 'and $INCLUDEONCE buffer

'reset altered variables
DataOffset = 0
inclevel = 0
subfuncn = 0
subfuncnlast = 0
lastLineReturn = 0
lastLine = 0
firstLine = 1
mainEndLine = 0
autoIncludeBuffer = -1
UserDefineList$ = UserDefineListPresets$
UserDefineCount = UserDefineCountPresets

FOR i = 0 TO constlast: constdefined(i) = 0: NEXT 'undefine constants

FOR i = 1 TO 27: defineaz(i) = "SINGLE": defineextaz(i) = "!": NEXT

DIM SHARED DataBinBuf: DataBinBuf = OpenBuffer%("O", tmpdir$ + "data.bin")

DIM SHARED MainTxtBuf: MainTxtBuf = OpenBuffer%("O", tmpdir$ + "main0.txt")
'Mark source-location tracking as explicitly controlled by this generated program.
'This one-time clear keeps $ErrorLocation:OFF independent of the legacy evnt() path.
WriteBufLine MainTxtBuf, "error_track_line(0,0,NULL);"
DIM SHARED DataTxtBuf: DataTxtBuf = OpenBuffer%("O", tmpdir$ + "maindata.txt")
DIM SHARED VWatchMainDispatchBuf: VWatchMainDispatchBuf = OpenBuffer%("O", tmpdir$ + "vw_main_dispatch.txt")
DIM SHARED VWatchMainSkipBuf: VWatchMainSkipBuf = OpenBuffer%("O", tmpdir$ + "vw_main_skip.txt")

DIM SHARED RegTxtBuf: RegTxtBuf = OpenBuffer%("O", tmpdir$ + "regsf.txt")

DIM SHARED FreeTxtBuf: FreeTxtBuf = OpenBuffer%("O", tmpdir$ + "mainfree.txt")
DIM SHARED RunTxtBuf: RunTxtBuf = OpenBuffer%("O", tmpdir$ + "runline.txt")

DIM SHARED ErrTxtBuf: ErrTxtBuf = OpenBuffer%("O", tmpdir$ + "mainerr.txt")
'i. check the value of error_line
'ii. jump to the appropriate label
errorlabels = 0
WriteBufLine ErrTxtBuf, "if (!error_handler_history) error_handler_history = qbs_new(0, 0);"
WriteBufLine ErrTxtBuf, "if (error_occurred){ error_occurred=0;"

DIM SHARED ChainTxtBuf: ChainTxtBuf = OpenBuffer%("O", tmpdir$ + "chain.txt")
DIM SHARED InpChainTxtBuf: InpChainTxtBuf = OpenBuffer%("O", tmpdir$ + "inpchain.txt")

DIM SHARED TimeTxtBuf: TimeTxtBuf = OpenBuffer%("O", tmpdir$ + "ontimer.txt")
DIM SHARED TimejTxtBuf: TimejTxtBuf = OpenBuffer%("O", tmpdir$ + "ontimerj.txt")

'*****#26 used for locking qb64pe

DIM SHARED KeyTxtBuf: KeyTxtBuf = OpenBuffer%("O", tmpdir$ + "onkey.txt")
DIM SHARED KeyjTxtBuf: KeyjTxtBuf = OpenBuffer%("O", tmpdir$ + "onkeyj.txt")

DIM SHARED StrigTxtBuf: StrigTxtBuf = OpenBuffer%("O", tmpdir$ + "onstrig.txt")
DIM SHARED StrigjTxtBuf: StrigjTxtBuf = OpenBuffer%("O", tmpdir$ + "onstrigj.txt")

gosubid = 1
'to be included whenever return without a label is called

'return [label] in QBASIC was not possible in a sub/function, but QB64 will support this
'special codes will represent special return conditions:
'0=return from main to calling sub/function/proc by return [NULL];
'1... a global number representing a return point after a gosub
'note: RETURN [label] should fail if a "return [NULL];" type return is required
DIM SHARED RetTxtBuf: RetTxtBuf = OpenBuffer%("O", tmpdir$ + "ret0.txt")
WriteBufLine RetTxtBuf, "if (next_return_point){"
WriteBufLine RetTxtBuf, "next_return_point--;"
WriteBufLine RetTxtBuf, "switch(return_point[next_return_point]){"
WriteBufLine RetTxtBuf, "case 0:"

WriteBufLine RetTxtBuf, "return;"

WriteBufLine RetTxtBuf, "break;"

continueline = 0
endifs = 0
lineelseused = 0
continuelinefrom = 0
linenumber = 0
reallinenumber = 0
declaringlibrary = 0

WriteBufLine MainTxtBuf, "S_0:;" 'note: REQUIRED by run statement

IF UseGL THEN gl_include_content


'ide specific
IF idemode THEN GOTO ideret3

DO
    compileline:
    prepass = 0
    IF recompile GOTO do_recompile

    stringprocessinghappened = 0

    IF continuelinefrom THEN
        start = continuelinefrom
        continuelinefrom = 0
        GOTO contline
    END IF

    'begin a new line

    impliedendif = 0
    THENGOTO = 0
    continueline = 0
    endifs = 0
    lineelseused = 0
    newif = 0
    layoutcontinuations = ""

    'apply metacommands from previous line
    IF addmetadynamic = 1 THEN addmetadynamic = 0: DynamicMode = 1
    IF addmetastatic = 1 THEN addmetastatic = 0: DynamicMode = 0

    'a3$ is passed in idemode, from $include and CLI lastLine trigger
    IF idemode = 0 AND inclevel = 0 AND lastLine = 0 THEN
        a3$ = lineinput3$ 'otherwise read from source
        IF a3$ = CHR$(13) THEN EXIT DO 'check for end
    END IF
    IF lastLine = 1 AND mainEndLine = 0 THEN mainEndLine = 1
    'perform auto-including according to code position
    IF firstLine = 1 OR (mainEndLine = 1 AND firstLine = 3) OR lastLine = 1 THEN
        lineBackup$ = a3$ 'backup the real line
        GOSUB setPrecompFlags
        GOSUB autoIncludeManager
        a3$ = lineBackup$
        idecompiledline$ = a3$ 'also restore compiled line for IDE ops
        'start of pass, reset formatting to defaults after auto-includes
        IDEAutoIndent = DEFAutoIndent: IDEAutoLayout = DEFAutoLayout
    END IF

    linenumber = linenumber + 1
    reallinenumber = reallinenumber + 1
    layout = ""
    layoutok = 1

    IF idemode = 0 AND NOT QuietMode THEN
        maxprogresswidth = 50 'arbitrary
        percentage = INT(reallinenumber / totallinenumber * 100)
        percentagechars = INT(maxprogresswidth * reallinenumber / totallinenumber)
        IF percentage <> prevpercentage AND percentagechars <> prevpercentagechars THEN
            prevpercentage = percentage
            prevpercentagechars = percentagechars
            IF ConsoleMode THEN
                PRINT "[" + STRING$(percentagechars, ".") + SPACE$(maxprogresswidth - percentagechars) + "]" + STR$(percentage) + "%";
                IF os$ = "LNX" THEN
                    PRINT CHR$(27) + "[A"
                ELSE
                    PRINT CHR$(13);
                END IF
            ELSE
                LOCATE , 1
                PRINT STRING$(percentagechars, 219) + STRING$(maxprogresswidth - percentagechars, 176) + STR$(percentage) + "%";
            END IF
        END IF
    END IF

    layoutoriginal$ = a3$
    a3$ = LTRIM$(RTRIM$(a3$))
    wholeline = a3$

    IF InvalidLine(linenumber) THEN
        IF idemode GOTO ideret4 ELSE GOTO skip_invalidated_line
    END IF

    layoutcomment$ = "" 'clear any previous layout comment
    lhscontrollevel = controllevel

    linefragment = "[INFORMATION UNAVAILABLE]"
    IF LEN(a3$) = 0 THEN GOTO finishednonexec
    IF Debug THEN PRINT #9, "########" + a3$ + "########"

    layoutdone = 1 'validates layout of any following goto finishednonexec/finishedline

    a3u$ = UCASE$(a3$)

    'QB64 Metacommands
    IF ASC(a3$) = 36 THEN '$

        'precompiler commands should always be executed FIRST.
        IF a3u$ = "$END IF" OR a3u$ = "$ENDIF" THEN
            IF DefineElse(ExecCounter) = 0 THEN a$ = "$END IF without $IF": GOTO errmes
            DefineElse(ExecCounter) = 0 'We no longer have an $IF block at this level
            ExecCounter = ExecCounter - 1
            layout$ = SCase$("$End If")
            controltype(controllevel) = 0
            controllevel = controllevel - 1
            GOTO finishednonexec
        END IF

        IF LEFT$(a3u$, 4) = "$IF " THEN
            'prevents code from being placed before 'CASE condition' in a SELECT CASE block
            IF SelectCaseCounter > 0 AND SelectCaseHasCaseBlock(SelectCaseCounter) = 0 THEN
                a$ = "Expected CASE expression": GOTO errmes
            END IF

            temp$ = LTRIM$(MID$(a3u$, 4)) 'strip off the $IF and extra spaces
            temp$ = RTRIM$(LEFT$(temp$, LEN(temp$) - 4)) 'and strip off the THEN and extra spaces
            temp = 0
            IF temp = 0 THEN tempOp$ = "<=": temp = INSTR(temp$, tempOp$)
            IF temp = 0 THEN tempOp$ = "=<": temp = INSTR(temp$, tempOp$): tempOp$ = "<="
            IF temp = 0 THEN tempOp$ = ">=": temp = INSTR(temp$, tempOp$)
            IF temp = 0 THEN tempOp$ = "=>": temp = INSTR(temp$, tempOp$): tempOp$ = ">="
            IF temp = 0 THEN tempOp$ = "<>": temp = INSTR(temp$, tempOp$)
            IF temp = 0 THEN tempOp$ = "><": temp = INSTR(temp$, tempOp$): tempOp$ = "<>"
            IF temp = 0 THEN tempOp$ = "=": temp = INSTR(temp$, tempOp$)
            IF temp = 0 THEN tempOp$ = ">": temp = INSTR(temp$, tempOp$)
            IF temp = 0 THEN tempOp$ = "<": temp = INSTR(temp$, tempOp$)

            ExecCounter = ExecCounter + 1
            ExecLevel(ExecCounter) = -1 'default to a skip value
            DefineElse(ExecCounter) = 1 '1 says we have an $IF statement at this level
            result = EvalPreIF(temp$, a$)
            IF a$ <> "" THEN GOTO errmes
            IF result <> 0 THEN
                ExecLevel(ExecCounter) = ExecLevel(ExecCounter - 1) 'So we inherit the execlevel from above
                IF ExecLevel(ExecCounter) = 0 THEN DefineElse(ExecCounter) = DefineElse(ExecCounter) OR 4 'Else if used and condition found
            END IF

            controllevel = controllevel + 1
            controltype(controllevel) = 6
            IF temp = 0 THEN layout$ = SCase$("$If ") + temp$ + SCase$(" Then"): GOTO finishednonexec 'no = sign in the $IF statement, so we're going to assume the user is doing something like $IF flag
            l$ = RTRIM$(LEFT$(temp$, temp - 1)): r$ = LTRIM$(MID$(temp$, temp + LEN(tempOp$)))
            layout$ = SCase$("$If ") + l$ + " " + tempOp$ + " " + r$ + SCase$(" Then")
            GOTO finishednonexec
        END IF

        IF a3u$ = "$ELSE" THEN
            IF DefineElse(ExecCounter) = 0 THEN a$ = "$ELSE without $IF": GOTO errmes
            IF DefineElse(ExecCounter) AND 2 THEN a$ = "$IF block already has $ELSE statement in it": GOTO errmes
            DefineElse(ExecCounter) = DefineElse(ExecCounter) OR 2 'set the flag to declare an $ELSE already in this block
            IF DefineElse(ExecCounter) AND 4 THEN 'If we executed code in a previous IF or ELSE IF statement, we can't do it here
                ExecLevel(ExecCounter) = -1 'So we inherit the execlevel from above
            ELSE
                ExecLevel(ExecCounter) = ExecLevel(ExecCounter - 1) 'If we were processing code before, code after this segment is going to be SKIPPED
            END IF
            layout$ = SCase$("$Else")
            lhscontrollevel = lhscontrollevel - 1
            GOTO finishednonexec
        END IF

        IF LEFT$(a3u$, 5) = "$ELSE" THEN
            temp$ = LTRIM$(MID$(a3u$, 6))
            IF LEFT$(temp$, 3) = "IF " THEN
                IF DefineElse(ExecCounter) = 0 THEN a$ = "$ELSE IF without $IF": GOTO errmes
                IF DefineElse(ExecCounter) AND 2 THEN a$ = "$ELSE IF cannot follow $ELSE": GOTO errmes
                IF RIGHT$(temp$, 5) <> " THEN" THEN a$ = "$ELSE IF without THEN": GOTO errmes
                temp$ = LTRIM$(MID$(temp$, 3)) 'strip off the IF and extra spaces
                temp$ = RTRIM$(LEFT$(temp$, LEN(temp$) - 4)) 'and strip off the THEN and extra spaces
                IF DefineElse(ExecCounter) AND 4 THEN 'If we executed code in a previous IF or ELSE IF statement, we can't do it here
                    ExecLevel(ExecCounter) = -1
                ELSE
                    result = EvalPreIF(temp$, a$)
                    IF a$ <> "" THEN GOTO errmes
                    IF result <> 0 THEN
                        ExecLevel(ExecCounter) = ExecLevel(ExecCounter - 1) 'So we inherit the execlevel from above
                        IF ExecLevel(ExecCounter) = 0 THEN DefineElse(ExecCounter) = DefineElse(ExecCounter) OR 4 'Else if used and condition found
                    END IF
                END IF


                lhscontrollevel = lhscontrollevel - 1
                temp = INSTR(temp$, "=")
                IF temp = 0 THEN layout$ = SCase$("$ElseIf ") + temp$ + SCase$(" Then"): GOTO finishednonexec 'no = sign in the $IF statement, so we're going to assume the user is doing something like $IF flag
                l$ = RTRIM$(LEFT$(temp$, temp - 1)): r$ = LTRIM$(MID$(temp$, temp + 1))
                layout$ = SCase$("$ElseIf ") + l$ + " = " + r$ + SCase$(" Then")
                GOTO finishednonexec
            END IF
        END IF

        IF ExecLevel(ExecCounter) THEN 'don't check for any more metacommands except the one's which worth with the precompiler
            layoutdone = 0
            GOTO finishednonexec 'we don't check for anything inside lines that we've marked for skipping
        END IF

        IF LEFT$(a3u$, 5) = "$LET " THEN
            temp$ = a3u$
            temp$ = LTRIM$(MID$(temp$, 5)) 'simply shorten our string to parse
            'For starters, let's make certain that we have 3 elements to deal with
            temp = INSTR(temp$, "=") 'without an = in there, we can't get a value from the left and right side
            l$ = RTRIM$(LEFT$(temp$, temp - 1)): r$ = LTRIM$(MID$(temp$, temp + 1))
            layout$ = SCase$("$Let ") + l$ + " = " + r$
            SetPreLET l$, r$
            GOTO finishednonexec
        END IF

        IF a3u$ = "$COLOR:0" THEN
            layout$ = SCase$("$Color:0")
            IF GetRCStateVar(ColorSet) = 2 THEN a$ = "$COLOR:32 already set, cannot use both color sets together": GOTO errmes
            GOTO finishednonexec
        END IF
        IF a3u$ = "$COLOR:32" THEN
            layout$ = SCase$("$Color:32")
            IF GetRCStateVar(ColorSet) = 1 THEN a$ = "$COLOR:0 already set, cannot use both color sets together": GOTO errmes
            GOTO finishednonexec
        END IF

        IF a3u$ = "$INCLUDEONCE" THEN
            'just to catch it as keyword
            layout$ = SCase$("$IncludeOnce")
            GOTO finishednonexec
        END IF

        IF a3u$ = "$DEBUG" THEN
            layout$ = SCase$("$Debug")
            IF NoIDEMode THEN
                addWarning linenumber, inclevel, inclinenumber(inclevel), incname$(inclevel), "$DEBUG features only work from the IDE", ""
            END IF
            GOTO finishednonexec
        END IF

        IF a3u$ = "$CHECKING:OFF" THEN
            layout$ = SCase$("$Checking:Off")
            CheckingOn = 0
            IF GetRCStateVar(vWatchOn) = 1 AND NOT NoIDEMode AND inclevel = 0 THEN
                addWarning linenumber, inclevel, inclinenumber(inclevel), incname$(inclevel), "$DEBUG features won't work in these blocks", "$CHECKING:OFF"
            END IF
            GOTO finishednonexec
        END IF
        IF a3u$ = "$CHECKING:ON" THEN
            layout$ = SCase$("$Checking:On")
            CheckingOn = 1
            GOTO finishednonexec
        END IF

        IF a3u$ = "$ERRORLOCATION:ON" THEN
            layout$ = SCase$("$ErrorLocation:On")
            IF GetRCStateVar(ErrorLocationMode) <> 2 THEN
                a$ = "$ErrorLocation is a whole-program option and cannot be changed within the program": GOTO errmes
            END IF
            GOTO finishednonexec
        END IF
        IF a3u$ = "$ERRORLOCATION:OFF" THEN
            layout$ = SCase$("$ErrorLocation:Off")
            IF GetRCStateVar(ErrorLocationMode) = 2 THEN
                a$ = "$ErrorLocation is a whole-program option and cannot be changed within the program": GOTO errmes
            END IF
            GOTO finishednonexec
        END IF

        IF a3u$ = "$CONSOLE" THEN
            'just to catch it as keyword
            layout$ = SCase$("$Console")
            GOTO finishednonexec
        END IF
        IF a3u$ = "$CONSOLE:ONLY" THEN
            layout$ = SCase$("$Console:Only")
            SetDependency DEPENDENCY_CONSOLE_ONLY
            IF CheckingOn THEN WriteBufLine MainTxtBuf, "do{"
            WriteBufLine MainTxtBuf, "sub__dest(func__console());"
            WriteBufLine MainTxtBuf, "sub__source(func__console());"
            GOTO finishedline2 '!!
        END IF

        IF a3u$ = "$ASSERTS" THEN
            'just to catch it as keyword
            layout$ = SCase$("$Asserts")
            GOTO finishednonexec
        END IF
        IF a3u$ = "$ASSERTS:CONSOLE" THEN
            'just to catch it as keyword
            layout$ = SCase$("$Asserts:Console")
            GOTO finishednonexec
        END IF

        IF a3u$ = "$SCREENHIDE" THEN
            layout$ = SCase$("$ScreenHide")
            ScreenHideOn = 1
            GOTO finishednonexec
        END IF
        IF a3u$ = "$SCREENSHOW" THEN
            layout$ = SCase$("$ScreenShow")
            ScreenHideOn = 0
            GOTO finishednonexec
        END IF

        IF a3u$ = "$RESIZE:OFF" THEN
            layout$ = SCase$("$Resize:Off")
            ResizeOn = 0: ResizeScale = 0
            GOTO finishednonexec
        END IF
        IF a3u$ = "$RESIZE:ON" THEN
            layout$ = SCase$("$Resize:On")
            ResizeOn = 1: ResizeScale = 0
            GOTO finishednonexec
        END IF
        IF a3u$ = "$RESIZE:STRETCH" THEN
            layout$ = SCase$("$Resize:Stretch")
            ResizeOn = 1: ResizeScale = 1
            GOTO finishednonexec
        END IF
        IF a3u$ = "$RESIZE:SMOOTH" THEN
            layout$ = SCase$("$Resize:Smooth")
            ResizeOn = 1: ResizeScale = 2
            GOTO finishednonexec
        END IF

        IF LEFT$(a3u$, 12) = "$VERSIONINFO" THEN
            'Embed version info into the final binary (Windows only)
            FirstDelimiter = INSTR(a3u$, ":")
            SecondDelimiter = INSTR(FirstDelimiter + 1, a3u$, "=")
            IF FirstDelimiter = 0 OR SecondDelimiter = 0 OR SecondDelimiter = FirstDelimiter + 1 THEN
                a$ = "Expected $VERSIONINFO:key=value": GOTO errmes
            END IF

            VersionInfoKey$ = LTRIM$(RTRIM$(MID$(a3u$, FirstDelimiter + 1, SecondDelimiter - FirstDelimiter - 1)))
            VersionInfoValue$ = StrReplace$(LTRIM$(RTRIM$(MID$(a3$, SecondDelimiter + 1))), CHR$(34), "'")
            issueWarning = _FALSE ' only issue warnings if this is true

            SELECT CASE VersionInfoKey$
                CASE "FILEVERSION#"
                    GOSUB ValidateVersion
                    viFileVersionNum$ = VersionInfoValue$
                    IF viFileVersion$ = "" THEN viFileVersion$ = viFileVersionNum$
                    layout$ = SCase$("$VersionInfo:FILEVERSION#=") + VersionInfoValue$
                CASE "PRODUCTVERSION#"
                    GOSUB ValidateVersion
                    viProductVersionNum$ = VersionInfoValue$
                    IF viProductVersion$ = "" THEN viProductVersion$ = viProductVersionNum$
                    layout$ = SCase$("$VersionInfo:PRODUCTVERSION#=") + VersionInfoValue$
                CASE "COMPANYNAME"
                    viCompanyName$ = RemoveStringEnclosingPair(VersionInfoValue$, METACOMMAND_STRING_ENCLOSING_PAIR)
                    layout$ = SCase$("$VersionInfo:") + "CompanyName=" + VersionInfoValue$
                    issueWarning = _TRUE
                CASE "FILEDESCRIPTION"
                    viFileDescription$ = RemoveStringEnclosingPair(VersionInfoValue$, METACOMMAND_STRING_ENCLOSING_PAIR)
                    layout$ = SCase$("$VersionInfo:") + "FileDescription=" + VersionInfoValue$
                    issueWarning = _TRUE
                CASE "FILEVERSION"
                    viFileVersion$ = RemoveStringEnclosingPair(VersionInfoValue$, METACOMMAND_STRING_ENCLOSING_PAIR)
                    layout$ = SCase$("$VersionInfo:") + "FileVersion=" + VersionInfoValue$
                    issueWarning = _TRUE
                CASE "INTERNALNAME"
                    viInternalName$ = RemoveStringEnclosingPair(VersionInfoValue$, METACOMMAND_STRING_ENCLOSING_PAIR)
                    layout$ = SCase$("$VersionInfo:") + "InternalName=" + VersionInfoValue$
                    issueWarning = _TRUE
                CASE "LEGALCOPYRIGHT"
                    viLegalCopyright$ = RemoveStringEnclosingPair(VersionInfoValue$, METACOMMAND_STRING_ENCLOSING_PAIR)
                    layout$ = SCase$("$VersionInfo:") + "LegalCopyright=" + VersionInfoValue$
                    issueWarning = _TRUE
                CASE "LEGALTRADEMARKS"
                    viLegalTrademarks$ = RemoveStringEnclosingPair(VersionInfoValue$, METACOMMAND_STRING_ENCLOSING_PAIR)
                    layout$ = SCase$("$VersionInfo:") + "LegalTrademarks=" + VersionInfoValue$
                    issueWarning = _TRUE
                CASE "ORIGINALFILENAME"
                    viOriginalFilename$ = RemoveStringEnclosingPair(VersionInfoValue$, METACOMMAND_STRING_ENCLOSING_PAIR)
                    layout$ = SCase$("$VersionInfo:") + "OriginalFilename=" + VersionInfoValue$
                    issueWarning = _TRUE
                CASE "PRODUCTNAME"
                    viProductName$ = RemoveStringEnclosingPair(VersionInfoValue$, METACOMMAND_STRING_ENCLOSING_PAIR)
                    layout$ = SCase$("$VersionInfo:") + "ProductName=" + VersionInfoValue$
                    issueWarning = _TRUE
                CASE "PRODUCTVERSION"
                    viProductVersion$ = RemoveStringEnclosingPair(VersionInfoValue$, METACOMMAND_STRING_ENCLOSING_PAIR)
                    layout$ = SCase$("$VersionInfo:") + "ProductVersion=" + VersionInfoValue$
                    issueWarning = _TRUE
                CASE "COMMENTS"
                    viComments$ = RemoveStringEnclosingPair(VersionInfoValue$, METACOMMAND_STRING_ENCLOSING_PAIR)
                    layout$ = SCase$("$VersionInfo:") + "Comments=" + VersionInfoValue$
                    issueWarning = _TRUE
                CASE "WEB"
                    viWeb$ = RemoveStringEnclosingPair(VersionInfoValue$, METACOMMAND_STRING_ENCLOSING_PAIR)
                    layout$ = SCase$("$VersionInfo:") + "Web=" + VersionInfoValue$
                    issueWarning = _TRUE
                CASE ELSE
                    a$ = "Invalid key. (Use FILEVERSION#, PRODUCTVERSION#, CompanyName, FileDescription, FileVersion, InternalName, LegalCopyright, LegalTrademarks, OriginalFilename, ProductName, ProductVersion, Comments or Web)"
                    GOTO errmes
            END SELECT

            ' Generate warnings if needed
            IF issueWarning AND NOT IgnoreWarnings THEN
                IF NOT HasStringEnclosingPair(VersionInfoValue$, METACOMMAND_STRING_ENCLOSING_PAIR) THEN
                    addWarning linenumber, inclevel, inclinenumber(inclevel), incname$(inclevel), "Missing string bracket delimiters (" + METACOMMAND_STRING_ENCLOSING_PAIR + ")", VersionInfoValue$
                END IF
            END IF

            VersionInfoSet = _TRUE

            GOTO finishednonexec

            ValidateVersion:
            'Check if only numbers and commas (4 comma-separated values)
            IF LEN(VersionInfoValue$) = 0 THEN a$ = "Expected $VERSIONINFO:" + VersionInfoKey$ + "=#,#,#,# (4 comma-separated numeric values: major, minor, revision and build)": GOTO errmes
            viCommas = 0
            FOR i = 1 TO LEN(VersionInfoValue$)
                IF ASC(VersionInfoValue$, i) = 44 THEN viCommas = viCommas + 1
                IF INSTR("0123456789,", MID$(VersionInfoValue$, i, 1)) = 0 OR (i = LEN(VersionInfoValue$) AND viCommas <> 3) OR RIGHT$(VersionInfoValue$, 1) = "," THEN
                    a$ = "Expected $VERSIONINFO:" + VersionInfoKey$ + "=#,#,#,# (4 comma-separated numeric values: major, minor, revision and build)": GOTO errmes
                END IF
            NEXT
            RETURN
        END IF

        IF LEFT$(a3u$, 6) = "$EMBED" THEN
            a$ = "Expected $EMBED:'filename','handle'"
            'check for filename
            bra = INSTR(a3u$, "'"): IF bra = 0 GOTO errmes
            ket = INSTR(bra + 1, a3u$, "'"): IF ket = 0 GOTO errmes
            EmbedFile$ = _TRIM$(MID$(a3$, bra + 1, ket - bra - 1))
            IF LEN(EmbedFile$) = 0 GOTO errmes
            'check for handle
            bra = INSTR(ket + 1, a3u$, "'"): IF bra = 0 GOTO errmes
            ket = INSTR(bra + 1, a3u$, "'"): IF ket = 0 GOTO errmes
            EmbedHandle$ = _TRIM$(MID$(a3$, bra + 1, ket - bra - 1))
            IF LEN(EmbedHandle$) = 0 GOTO errmes
            'fix layout
            layout$ = SCase$("$Embed:'") + EmbedFile$ + "','" + EmbedHandle$ + "'" + MID$(a3$, ket + 1)
            'verify path/file existence
            EmbedPath$ = ""
            IF LEFT$(EmbedFile$, 2) = "./" OR LEFT$(EmbedFile$, 2) = ".\" THEN
                IF NoIDEMode THEN
                    EmbedPath$ = path.source$
                    IF LEN(EmbedPath$) > 0 AND RIGHT$(EmbedPath$, 1) <> pathsep$ THEN EmbedPath$ = EmbedPath$ + pathsep$
                ELSE
                    IF LEN(ideprogname) THEN EmbedPath$ = idepath$ + pathsep$
                END IF
                EmbedFile$ = EmbedPath$ + MID$(EmbedFile$, 3)
            ELSEIF INSTR(EmbedFile$, "/") OR INSTR(EmbedFile$, "\") THEN
                FOR i = LEN(EmbedFile$) TO 1 STEP -1
                    IF MID$(EmbedFile$, i, 1) = "/" OR MID$(EmbedFile$, i, 1) = "\" THEN
                        EmbedPath$ = LEFT$(EmbedFile$, i)
                        EmbedFileOnly$ = MID$(EmbedFile$, i + 1)
                        IF _DIREXISTS(EmbedPath$) = 0 THEN a$ = "File '" + EmbedFileOnly$ + "' not found": GOTO errmes
                        currentdir$ = _CWD$
                        CHDIR EmbedPath$
                        EmbedPath$ = _CWD$
                        CHDIR currentdir$
                        EmbedFile$ = EmbedPath$ + pathsep$ + EmbedFileOnly$
                        EXIT FOR
                    END IF
                NEXT
            END IF
            IF _FILEEXISTS(EmbedFile$) = 0 THEN a$ = "File '" + EmbedFile$ + "' not found": GOTO errmes
            'verify handle validity (Aa-Zz/0-9, begin with letter)
            SELECT CASE ASC(EmbedHandle$, 1)
                CASE 0 TO 64, 91 TO 96, 123 TO 255
                    a$ = "First char of Embed-Handle '" + EmbedHandle$ + "' must be a letter": GOTO errmes
            END SELECT
            FOR i = 2 TO LEN(EmbedHandle$)
                SELECT CASE ASC(EmbedHandle$, i)
                    CASE 0 TO 47, 58 TO 64, 91 TO 96, 123 TO 255
                        a$ = "Embed-Handle '" + EmbedHandle$ + "' has invalid chars, use Aa-Zz/0-9 only": GOTO errmes
                END SELECT
            NEXT i
            'check for duplicate definitions
            eflUB = UBOUND(embedFileList$, 2)
            FOR i = 0 TO eflUB
                IF embedFileList$(eflFile, i) = EmbedFile$ THEN
                    a$ = "File '" + EmbedFile$ + "' was already embedded in line"
                ELSEIF embedFileList$(eflHand, i) = EmbedHandle$ THEN
                    a$ = "Embed-Handle '" + EmbedHandle$ + "' is already used in line"
                ELSE
                    _CONTINUE
                END IF
                a$ = a$ + embedFileList$(eflLine, i): GOTO errmes
            NEXT i
            'register file for later checks and embedding
            FOR i = 0 TO eflUB
                IF embedFileList$(eflFile, i) = "" THEN EXIT FOR
            NEXT i
            IF i > eflUB THEN
                REDIM _PRESERVE embedFileList$(3, eflUB + 10)
                i = eflUB + 1
            END IF
            embedFileList$(eflLine, i) = STR$(linenumber) 'linenumber of this $EMBED
            embedFileList$(eflUsed, i) = "no" '           'referenced by _EMBEDDED$()
            embedFileList$(eflFile, i) = EmbedFile$
            embedFileList$(eflHand, i) = EmbedHandle$
            GOTO finishednonexec
        END IF

        IF LEFT$(a3u$, 11) = "$USELIBRARY" THEN
            'fix layout
            bra = INSTR(a3u$, "'"): ket = INSTR(bra + 1, a3u$, "'")
            UseLib$ = _TRIM$(MID$(a3$, bra + 1, ket - bra - 1))
            layout$ = SCase$("$UseLibrary:'") + UseLib$ + "'" + MID$(a3$, ket + 1)
            GOTO finishednonexec
        END IF

        IF LEFT$(a3u$, 8) = "$EXEICON" THEN
            'Basic syntax check. Multi-platform.
            IF ExeIconSet <> 0 THEN a$ = "$EXEICON already defined in line" + STR$(ExeIconSet): GOTO errmes
            FirstDelimiter = INSTR(a3u$, "'")
            IF FirstDelimiter = 0 THEN
                a$ = "Expected $EXEICON:'filename'": GOTO errmes
            ELSE
                SecondDelimiter = INSTR(FirstDelimiter + 1, a3u$, "'")
                IF SecondDelimiter = 0 THEN a$ = "Expected $EXEICON:'filename'": GOTO errmes
            END IF
            ExeIconFile$ = RTRIM$(LTRIM$(MID$(a3$, FirstDelimiter + 1, SecondDelimiter - FirstDelimiter - 1)))
            IF LEN(ExeIconFile$) = 0 THEN a$ = "Expected $EXEICON:'filename'": GOTO errmes
            layout$ = SCase$("$ExeIcon:'") + ExeIconFile$ + "'" + MID$(a3$, SecondDelimiter + 1)

            IconPath$ = ""
            IF LEFT$(ExeIconFile$, 2) = "./" OR LEFT$(ExeIconFile$, 2) = ".\" THEN
                'Relative to source file's folder
                IF NoIDEMode THEN
                    IconPath$ = path.source$
                    IF LEN(IconPath$) > 0 AND RIGHT$(IconPath$, 1) <> pathsep$ THEN IconPath$ = IconPath$ + pathsep$
                ELSE
                    IF LEN(ideprogname) THEN IconPath$ = idepath$ + pathsep$
                END IF

                ExeIconFile$ = IconPath$ + MID$(ExeIconFile$, 3)
            ELSEIF INSTR(ExeIconFile$, "/") OR INSTR(ExeIconFile$, "\") THEN
                FOR i = LEN(ExeIconFile$) TO 1 STEP -1
                    IF MID$(ExeIconFile$, i, 1) = "/" OR MID$(ExeIconFile$, i, 1) = "\" THEN
                        IconPath$ = LEFT$(ExeIconFile$, i)
                        ExeIconFileOnly$ = MID$(ExeIconFile$, i + 1)

                        IF _DIREXISTS(IconPath$) = 0 THEN a$ = "File '" + ExeIconFileOnly$ + "' not found": GOTO errmes

                        currentdir$ = _CWD$
                        CHDIR IconPath$
                        IconPath$ = _CWD$
                        CHDIR currentdir$

                        ExeIconFile$ = IconPath$ + pathsep$ + ExeIconFileOnly$
                        EXIT FOR
                    END IF
                NEXT
            END IF

            IF _FILEEXISTS(ExeIconFile$) = 0 THEN a$ = "File '" + ExeIconFile$ + "' not found": GOTO errmes

            ExeIconSet = linenumber
            SetDependency DEPENDENCY_ICON
            WriteBufLine ExtDepBuf, "ICON: " + _FULLPATH$(ExeIconFile$)
            IF CheckingOn THEN WriteBufLine MainTxtBuf, "do{"
            WriteBufLine MainTxtBuf, "sub__icon(NULL,NULL,0);"
            GOTO finishedline2
        END IF

        IF LEFT$(a3u$, 10) = "$UNSTABLE:" THEN
            layout$ = SCase$("$Unstable:")

            token$ = LTRIM$(RTRIM$(MID$(a3u$, 11)))

            SELECT CASE token$
                CASE "MIDI"
                    layout$ = layout$ + SCase$("Midi")
                    addWarning linenumber, inclevel, inclinenumber(inclevel), incname$(inclevel), "No longer required, feature is stable now", "$UNSTABLE:MIDI"

                CASE "HTTP"
                    layout$ = layout$ + SCase$("Http")
                    addWarning linenumber, inclevel, inclinenumber(inclevel), incname$(inclevel), "No longer required, feature is stable now", "$UNSTABLE:HTTP"

                CASE "TYPEFIELDS"
                    layout$ = layout$ + SCase$("TypeFields")
            END SELECT

            GOTO finishednonexec
        END IF

    END IF 'QB64 Metacommands

    IF ExecLevel(ExecCounter) THEN
        layoutdone = 0
        GOTO finishednonexec 'we don't check for anything inside lines that we've marked for skipping
    END IF


    linedataoffset = DataOffset

    entireline$ = lineformat(a3$): IF LEN(entireline$) = 0 THEN GOTO finishednonexec
    IF Error_Happened THEN GOTO errmes
    u$ = UCASE$(entireline$)

    newif = 0

    'Convert "CASE ELSE" to "CASE C-EL" to avoid confusing compiler
    'note: CASE does not have to begin on a new line
    s = 1
    i = INSTR(s, u$, "CASE" + sp + "ELSE")
    DO WHILE i
        skip = 0
        IF i <> 1 THEN
            IF MID$(u$, i - 1, 1) <> sp THEN skip = 1
        END IF
        IF i <> LEN(u$) - 8 THEN
            IF MID$(u$, i + 9, 1) <> sp THEN skip = 1
        END IF
        IF skip = 0 THEN
            MID$(entireline$, i) = "CASE" + sp + "C-EL"
            u$ = UCASE$(entireline$)
        END IF
        s = i + 9
        i = INSTR(s, u$, "CASE" + sp + "ELSE")
    LOOP

    n = numelements(entireline$)

    'line number?
    a = ASC(entireline$)
    IF (a >= 48 AND a <= 57) OR a = 46 THEN 'numeric
        label$ = getelement(entireline$, 1)
        IF validlabel(label$) THEN

            v = HashFind(label$, HASHFLAG_LABEL, ignore, r)
            addlabchk100:
            IF v THEN
                s = Labels(r).Scope
                IF s = subfuncn OR s = -1 THEN 'same scope?
                    IF s = -1 THEN Labels(r).Scope = subfuncn 'acquire scope
                    IF Labels(r).State = 1 THEN a$ = "Duplicate label (" + RTRIM$(Labels(r).cn) + ")": GOTO errmes
                    'acquire state 0 types
                    tlayout$ = RTRIM$(Labels(r).cn)
                    GOTO addlabaq100
                END IF 'same scope
                IF v = 2 THEN v = HashFindCont(ignore, r): GOTO addlabchk100
            END IF

            'does not exist
            nLabels = nLabels + 1: IF nLabels > Labels_Ubound THEN Labels_Ubound = Labels_Ubound * 2: REDIM _PRESERVE Labels(1 TO Labels_Ubound) AS Label_Type
            Labels(nLabels) = Empty_Label
            HashAdd label$, HASHFLAG_LABEL, nLabels
            r = nLabels
            Labels(r).cn = tlayout$
            Labels(r).Scope = subfuncn
            addlabaq100:
            Labels(r).State = 1
            Labels(r).Data_Offset = linedataoffset

            layout$ = tlayout$
            WriteBufLine MainTxtBuf, "LABEL_" + label$ + ":;"


            IF INSTR(label$, "p") THEN MID$(label$, INSTR(label$, "p"), 1) = "."
            IF RIGHT$(label$, 1) = "d" OR RIGHT$(label$, 1) = "s" THEN label$ = LEFT$(label$, LEN(label$) - 1)
            WriteBufLine MainTxtBuf, "last_line=" + label$ + ";"
            inclinenump$ = ""
            IF inclinenumber(inclevel) THEN
                inclinenump$ = "," + _TOSTR$(inclinenumber(inclevel))
                thisincname$ = getfilepath$(incname$(inclevel))
                thisincname$ = MID$(incname$(inclevel), LEN(thisincname$) + 1)
                inclinenump$ = inclinenump$ + "," + CHR$(34) + thisincname$ + CHR$(34)
            END IF
            IF CheckingOn THEN
                IF GetRCStateVar(vWatchOn) = 1 AND inclinenumber(inclevel) = 0 THEN temp$ = vWatchErrorCall$ ELSE temp$ = ""
                WriteBufLine MainTxtBuf, "if(qbevent){" + temp$ + "evnt(" + _TOSTR$(linenumber) + inclinenump$ + ");r=0;}"
            END IF
            IF n = 1 THEN GOTO finishednonexec
            entireline$ = getelements(entireline$, 2, n): u$ = UCASE$(entireline$): n = n - 1
            'note: fall through, numeric labels can be followed by alphanumeric label
        END IF 'validlabel
    END IF 'numeric
    'it wasn't a line number

    'label?
    'note: ignores possibility that this could be a single command SUB/FUNCTION (as in QBASIC?)
    IF n >= 2 THEN
        x2 = INSTR(entireline$, sp + ":")
        IF x2 THEN
            IF x2 = LEN(entireline$) - 1 THEN x3 = x2 + 1 ELSE x3 = x2 + 2
            a$ = LEFT$(entireline$, x2 - 1)

            CreatingLabel = 1
            IF validlabel(a$) THEN

                IF validname(a$) = 0 THEN a$ = "Invalid name": GOTO errmes

                v = HashFind(a$, HASHFLAG_LABEL, ignore, r)
                addlabchk:
                IF v THEN
                    s = Labels(r).Scope
                    IF s = subfuncn OR s = -1 THEN 'same scope?
                        IF s = -1 THEN Labels(r).Scope = subfuncn 'acquire scope
                        IF Labels(r).State = 1 THEN a$ = "Duplicate label (" + RTRIM$(Labels(r).cn) + ")": GOTO errmes
                        'acquire state 0 types
                        tlayout$ = RTRIM$(Labels(r).cn)
                        GOTO addlabaq
                    END IF 'same scope
                    IF v = 2 THEN v = HashFindCont(ignore, r): GOTO addlabchk
                END IF
                'does not exist
                nLabels = nLabels + 1: IF nLabels > Labels_Ubound THEN Labels_Ubound = Labels_Ubound * 2: REDIM _PRESERVE Labels(1 TO Labels_Ubound) AS Label_Type
                Labels(nLabels) = Empty_Label
                HashAdd a$, HASHFLAG_LABEL, nLabels
                r = nLabels
                Labels(r).cn = tlayout$
                Labels(r).Scope = subfuncn
                addlabaq:
                Labels(r).State = 1
                Labels(r).Data_Offset = linedataoffset
                Labels(r).SourceLineNumber = linenumber

                IF LEN(layout$) THEN layout$ = layout$ + sp + tlayout$ + ":" ELSE layout$ = tlayout$ + ":"

                WriteBufLine MainTxtBuf, "LABEL_" + a$ + ":;"
                inclinenump$ = ""
                IF inclinenumber(inclevel) THEN
                    inclinenump$ = "," + _TOSTR$(inclinenumber(inclevel))
                    thisincname$ = getfilepath$(incname$(inclevel))
                    thisincname$ = MID$(incname$(inclevel), LEN(thisincname$) + 1)
                    inclinenump$ = inclinenump$ + "," + CHR$(34) + thisincname$ + CHR$(34)
                END IF
                IF CheckingOn THEN
                    IF GetRCStateVar(vWatchOn) = 1 AND inclinenumber(inclevel) = 0 THEN temp$ = vWatchErrorCall$ ELSE temp$ = ""
                    WriteBufLine MainTxtBuf, "if(qbevent){" + temp$ + "evnt(" + _TOSTR$(linenumber) + inclinenump$ + ");r=0;}"
                END IF
                entireline$ = RIGHT$(entireline$, LEN(entireline$) - x3): u$ = UCASE$(entireline$)
                n = numelements(entireline$): IF n = 0 THEN GOTO finishednonexec
            END IF 'valid
        END IF 'includes sp+":"
    END IF 'n>=2

    'remove leading ":"
    DO WHILE ASC(u$) = 58 '":"
        IF LEN(layout$) THEN layout$ = layout$ + sp2 + ":" ELSE layout$ = ":"
        IF LEN(u$) = 1 THEN GOTO finishednonexec
        entireline$ = getelements(entireline$, 2, n): u$ = UCASE$(entireline$): n = n - 1
    LOOP

    'ELSE at the beginning of a line
    IF ASC(u$) = 69 THEN '"E"

        e1$ = getelement(u$, 1)

        IF e1$ = "ELSE" THEN
            a$ = "ELSE"
            IF n > 1 THEN continuelinefrom = 2
            GOTO gotcommand
        END IF

        IF e1$ = "ELSEIF" THEN
            IF n < 3 THEN a$ = "Expected ... THEN": GOTO errmes
            IF getelement(u$, n) = "THEN" THEN a$ = entireline$: GOTO gotcommand
            FOR i = 3 TO n - 1
                IF getelement(u$, i) = "THEN" THEN
                    a$ = getelements(entireline$, 1, i)
                    continuelinefrom = i + 1
                    GOTO gotcommand
                END IF
            NEXT
            a$ = "Expected THEN": GOTO errmes
        END IF

    END IF '"E"

    start = 1

    GOTO skipcontinit

    contline:

    n = numelements(entireline$)
    u$ = UCASE$(entireline$)

    skipcontinit:

    'jargon:
    'lineelseused - counts how many line ELSEs can POSSIBLY follow
    'endifs - how many C++ endifs "}" need to be added at the end of the line
    'lineelseused - counts the number of indwelling ELSE statements on a line
    'impliedendif - stops autoformat from adding "END IF"

    a$ = ""

    FOR i = start TO n
        e$ = getelement(u$, i)


        IF e$ = ":" THEN
            IF i = start THEN
                layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp2 + ":" ELSE layout$ = ":"
                IF i <> n THEN continuelinefrom = i + 1
                GOTO finishednonexec
            END IF
            IF i <> n THEN continuelinefrom = i
            GOTO gotcommand
        END IF


        'begin scanning an 'IF' statement
        IF e$ = "IF" AND a$ = "" THEN newif = 1


        IF e$ = "THEN" OR (e$ = "GOTO" AND newif = 1) THEN
            IF newif = 0 THEN a$ = "THEN without IF": GOTO errmes
            newif = 0
            IF lineelseused > 0 THEN lineelseused = lineelseused - 1
            IF e$ = "GOTO" THEN
                IF i = n THEN a$ = "Expected IF expression GOTO label": GOTO errmes
                i = i - 1
            END IF
            a$ = a$ + sp + e$ '+"THEN"/"GOTO"
            IF i <> n THEN continuelinefrom = i + 1: endifs = endifs + 1
            GOTO gotcommand
        END IF


        IF e$ = "ELSE" THEN

            IF start = i THEN
                IF lineelseused >= 1 THEN
                    'note: more than one else used (in a row) on this line, so close first if with an 'END IF' first
                    'note: parses 'END IF' then (after continuelinefrom) parses 'ELSE'
                    'consider the following: (square brackets make reading easier)
                    'eg. if a=1 then [if b=2 then c=2 else d=2] else e=3
                    impliedendif = 1: a$ = "END" + sp + "IF"
                    endifs = endifs - 1
                    continuelinefrom = i
                    lineelseused = lineelseused - 1
                    GOTO gotcommand
                END IF
                'follow up previously encountered 'ELSE' by applying 'ELSE'
                a$ = "ELSE": continuelinefrom = i + 1
                lineelseused = lineelseused + 1
                GOTO gotcommand
            END IF 'start=i

            'apply everything up to (but not including) 'ELSE'
            continuelinefrom = i
            GOTO gotcommand
        END IF '"ELSE"


        e$ = getelement(entireline$, i): IF a$ = "" THEN a$ = e$ ELSE a$ = a$ + sp + e$
    NEXT


    'we're reached the end of the line
    IF endifs > 0 THEN
        endifs = endifs - 1
        impliedendif = 1: entireline$ = entireline$ + sp + ":" + sp + "END" + sp + "IF": n = n + 3
        i = i + 1 'skip the ":" (i is now equal to n+2)
        continuelinefrom = i
        GOTO gotcommand
    END IF


    gotcommand:

    dynscope = 0

    ca$ = a$
    a$ = eleucase$(ca$) '***REVISE THIS SECTION LATER***


    layoutdone = 0

    linefragment = a$
    IF Debug THEN PRINT #9, a$
    n = numelements(a$)
    IF n = 0 THEN GOTO finishednonexec

    'convert non-UDT dimensioned periods to _046_
    IF INSTR(ca$, sp + "." + sp) THEN
        a3$ = getelement(ca$, 1)
        except = 0
        aa$ = a3$ + sp 'rebuilt a$ (always has a trailing spacer)
        lastfuse = -1
        FOR x = 2 TO n
            a2$ = getelement(ca$, x)
            IF except = 1 THEN except = 2: GOTO udtperiod 'skip element name
            IF a2$ = "." AND x <> n THEN
                IF except = 2 THEN except = 1: GOTO udtperiod 'sub-element of UDT

                IF a3$ = ")" THEN
                    'assume it was something like typevar(???).x and treat as a UDT
                    except = 1
                    GOTO udtperiod
                END IF

                'find an ID of that type
                try = findid(UCASE$(a3$))
                IF Error_Happened THEN GOTO errmes
                DO WHILE try
                    IF ((id.t AND ISUDT) <> 0) OR ((id.arraytype AND ISUDT) <> 0) THEN
                        except = 1
                        GOTO udtperiod
                    END IF
                    IF try = 2 THEN findanotherid = 1: try = findid(UCASE$(a3$)) ELSE try = 0
                    IF Error_Happened THEN GOTO errmes
                LOOP
                'not a udt; fuse lhs & rhs with _046_
                IF isalpha(ASC(a3$)) = 0 AND lastfuse <> x - 2 THEN a$ = "Invalid '.'": GOTO errmes
                aa$ = LEFT$(aa$, LEN(aa$) - 1) + fix046$
                lastfuse = x
                GOTO periodfused
            END IF '"."
            except = 0
            udtperiod:
            aa$ = aa$ + a2$ + sp
            periodfused:
            a3$ = a2$
        NEXT
        a$ = LEFT$(aa$, LEN(aa$) - 1)
        ca$ = a$
        a$ = eleucase$(ca$)
        n = numelements(a$)
    END IF

    arrayprocessinghappened = 0

    firstelement$ = getelement(a$, 1)
    secondelement$ = getelement(a$, 2)
    thirdelement$ = getelement(a$, 3)

    'non-executable section

    IF n = 1 THEN
        IF firstelement$ = "'" THEN layoutdone = 1: GOTO finishednonexec 'nop
    END IF

    IF n <= 2 THEN
        IF firstelement$ = "DATA" THEN
            l$ = SCase$("Data")
            IF n = 2 THEN

                e$ = SPACE$((LEN(secondelement$) - 1) \ 2)
                FOR x = 1 TO LEN(e$)
                    v1 = ASC(secondelement$, x * 2)
                    v2 = ASC(secondelement$, x * 2 + 1)
                    IF v1 < 65 THEN v1 = v1 - 48 ELSE v1 = v1 - 55
                    IF v2 < 65 THEN v2 = v2 - 48 ELSE v2 = v2 - 55
                    ASC(e$, x) = v1 + v2 * 16
                NEXT
                l$ = l$ + sp + e$
            END IF 'n=2

            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$

            GOTO finishednonexec
        END IF
    END IF



    'declare library
    IF declaringlibrary THEN

        IF firstelement$ = "END" THEN
            IF n <> 2 OR secondelement$ <> "DECLARE" THEN a$ = "Expected END DECLARE": GOTO errmes
            declaringlibrary = 0
            l$ = SCase$("End" + sp + "Declare")
            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
            GOTO finishednonexec
        END IF 'end declare

        declaringlibrary = 2

        IF firstelement$ = "SUB" OR firstelement$ = "FUNCTION" THEN
            GOTO declaresubfunc2
        END IF

        a$ = "Expected SUB/FUNCTION definition or END DECLARE": GOTO errmes
    END IF 'declaringlibrary

    'check TYPE declarations (created on prepass)
    IF definingtype THEN

        IF firstelement$ = "END" THEN
            IF n <> 2 OR secondelement$ <> "TYPE" THEN a$ = "Expected END TYPE": GOTO errmes
            definingtype = 0
            l$ = SCase$("End" + sp + "Type")
            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
            GOTO finishednonexec
        END IF

        'IF n < 3 THEN definingtypeerror = linenumber: a$ = "Expected element-name AS type or AS type element-list": GOTO errmes
        IF n < 3 THEN a$ = "Expected element-name AS type or AS type element-list": GOTO errmes
        definingtype = 2
        IF firstelement$ = "AS" THEN
            'Support TYPE lines in the form:
            '    AS <type> a, b(0 TO 3), c(1, 2)
            'The leading AS type applies to the whole line.
            'A second AS token on the same declaration line is invalid.
            declStart = 0
            declModeStart = 0
            FOR i = 3 TO n
                thisElement$ = getelement$(a$, i)
                IF UDTFieldModeToken%(thisElement$) THEN
                    IF declModeStart = 0 THEN declModeStart = i
                ELSEIF validname(thisElement$) THEN
                    IF declModeStart THEN
                        t$ = getelements$(a$, 2, declModeStart - 1)
                    ELSE
                        t$ = getelements$(a$, 2, i - 1)
                    END IF
                    typ = typname2typ(t$)
                    IF Error_Happened THEN GOTO errmes
                    IF typ THEN
                        declStart = i
                        EXIT FOR
                    END IF
                END IF
            NEXT
            IF declStart = 0 THEN a$ = "Undefined type": GOTO errmes

            l$ = SCase$("As")
            IF declModeStart THEN layoutMemberStart = declModeStart ELSE layoutMemberStart = declStart
            IF typ AND ISUDT THEN
                t$ = RTRIM$(udtxcname(typ AND UDTMASK))
                l$ = l$ + sp + t$
            ELSE
                l$ = l$ + sp + SCase2$(t$)
            END IF

            ' Normalize the member declaration for layout / auto-format output.
            ' Keep array declarators and dotted member syntax compact and readable.
            '
            l$ = l$ + sp + CompactMemberRefLayout$(getelements$(ca$, layoutMemberStart, n))
            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
        ELSE
            layoutFieldMode = 0
            layoutNameIndex = 1
            IF UDTFieldModeToken%(getelement$(a$, 1)) THEN
                fieldToken$ = getelement$(a$, 1)
                UDTApplyFieldMode fieldToken$, layoutFieldMode
                IF Error_Happened THEN GOTO errmes
                layoutNameIndex = 2
            END IF
            IF layoutNameIndex = 2 THEN
                l$ = UDTFieldModeLayout$(layoutFieldMode) + sp + getelement$(ca$, layoutNameIndex)
            ELSE
                l$ = getelement$(ca$, layoutNameIndex)
            END IF
            ii = layoutNameIndex + 1
            DO WHILE ii <= n
                fieldToken$ = getelement$(a$, ii)
                IF UDTFieldModeToken%(fieldToken$) = 0 THEN EXIT DO
                UDTApplyFieldMode fieldToken$, layoutFieldMode
                IF Error_Happened THEN GOTO errmes
                l$ = l$ + sp + UDTFieldModeLayout$(UDTFieldModeToken%(fieldToken$))
                ii = ii + 1
            LOOP
            IF ii < n THEN
                IF getelement$(a$, ii) = "(" THEN
                    b2 = 1
                    i3 = ii + 1
                    DO WHILE i3 <= n
                        nextElement$ = getelement$(a$, i3)
                        IF nextElement$ = "(" THEN b2 = b2 + 1
                        IF nextElement$ = ")" THEN
                            b2 = b2 - 1
                            IF b2 = 0 THEN EXIT DO
                        END IF
                        i3 = i3 + 1
                    LOOP
                    IF b2 <> 0 THEN a$ = "Expected )": GOTO errmes
                    l$ = l$ + CompactMemberRefLayout$(getelements$(ca$, ii, i3))
                    ii = i3 + 1
                END IF
            END IF
            DO WHILE ii <= n
                fieldToken$ = getelement$(a$, ii)
                IF UDTFieldModeToken%(fieldToken$) = 0 THEN EXIT DO
                UDTApplyFieldMode fieldToken$, layoutFieldMode
                IF Error_Happened THEN GOTO errmes
                l$ = l$ + sp + UDTFieldModeLayout$(UDTFieldModeToken%(fieldToken$))
                ii = ii + 1
            LOOP
            IF ii >= n OR getelement$(a$, ii) <> "AS" THEN a$ = "Expected element-name AS type or AS type element-list": GOTO errmes
            l$ = l$ + sp + SCase$("As")
            typeLast = n
            DO WHILE typeLast >= ii + 1
                fieldToken$ = getelement$(a$, typeLast)
                IF UDTFieldModeToken%(fieldToken$) = 0 THEN EXIT DO
                UDTApplyFieldMode fieldToken$, layoutFieldMode
                IF Error_Happened THEN GOTO errmes
                typeLast = typeLast - 1
            LOOP
            IF typeLast < ii + 1 THEN a$ = "Expected type": GOTO errmes
            t$ = getelements$(a$, ii + 1, typeLast)
            typ = typname2typ(t$)
            IF Error_Happened THEN GOTO errmes
            IF typ = 0 THEN a$ = "Undefined type": GOTO errmes
            IF typ AND ISUDT THEN
                t$ = RTRIM$(udtxcname(typ AND UDTMASK))
                l$ = l$ + sp + t$
            ELSE
                l$ = l$ + sp + SCase2$(t$)
            END IF
            DO WHILE typeLast < n
                typeLast = typeLast + 1
                l$ = l$ + sp + UDTFieldModeLayout$(UDTFieldModeToken%(getelement$(a$, typeLast)))
            LOOP
            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
        END IF
        GOTO finishednonexec

    END IF 'defining type

    IF firstelement$ = "TYPE" THEN
        IF n <> 2 THEN a$ = "Expected TYPE type-name": GOTO errmes
        l$ = SCase$("Type") + sp + getelement(ca$, 2)
        layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
        definingtype = 1
        definingtypeerror = linenumber
        GOTO finishednonexec
    END IF

    'skip DECLARE SUB/FUNCTION
    IF n >= 1 THEN
        IF firstelement$ = "DECLARE" THEN

            IF secondelement$ = "LIBRARY" OR secondelement$ = "DYNAMIC" OR secondelement$ = "CUSTOMTYPE" OR secondelement$ = "STATIC" THEN

                declaringlibrary = 1
                dynamiclibrary = 0
                customtypelibrary = 0
                indirectlibrary = 0
                staticlinkedlibrary = 0

                x = 3
                l$ = SCase$("Declare" + sp + "Library")

                IF secondelement$ = "DYNAMIC" THEN
                    e$ = getelement$(a$, 3): IF e$ <> "LIBRARY" THEN a$ = "Expected DYNAMIC LIBRARY " + CHR$(34) + "..." + CHR$(34): GOTO errmes
                    dynamiclibrary = 1
                    x = 4
                    l$ = SCase$("Declare" + sp + "Dynamic" + sp + "Library")
                    IF n = 3 THEN a$ = "Expected DECLARE DYNAMIC LIBRARY " + CHR$(34) + "..." + CHR$(34): GOTO errmes
                    indirectlibrary = 1
                END IF

                IF secondelement$ = "CUSTOMTYPE" THEN
                    e$ = getelement$(a$, 3): IF e$ <> "LIBRARY" THEN a$ = "Expected CUSTOMTYPE LIBRARY": GOTO errmes
                    customtypelibrary = 1
                    x = 4
                    l$ = SCase$("Declare" + sp + "CustomType" + sp + "Library")
                    indirectlibrary = 1
                END IF

                IF secondelement$ = "STATIC" THEN
                    e$ = getelement$(a$, 3): IF e$ <> "LIBRARY" THEN a$ = "Expected STATIC LIBRARY": GOTO errmes
                    x = 4
                    l$ = SCase$("Declare" + sp + "Static" + sp + "Library")
                    staticlinkedlibrary = 1
                END IF

                sfdeclare = 0: sfheader = 0

                IF n >= x THEN

                    sfdeclare = 1

                    addlibrary:

                    libname$ = ""
                    headername$ = ""


                    'assume library name in double quotes follows
                    'assume library is in main qb64pe folder
                    x$ = getelement$(ca$, x)
                    IF ASC(x$) <> 34 THEN a$ = "Expected LIBRARY " + CHR$(34) + "..." + CHR$(34): GOTO errmes
                    x$ = RIGHT$(x$, LEN(x$) - 1)
                    z = INSTR(x$, CHR$(34))
                    IF z = 0 THEN a$ = "Expected LIBRARY " + CHR$(34) + "..." + CHR$(34): GOTO errmes
                    x$ = LEFT$(x$, z - 1)

                    IF dynamiclibrary <> 0 AND LEN(x$) = 0 THEN a$ = "Expected DECLARE DYNAMIC LIBRARY " + CHR$(34) + "..." + CHR$(34): GOTO errmes
                    IF customtypelibrary <> 0 AND LEN(x$) = 0 THEN a$ = "Expected DECLARE CUSTOMTYPE LIBRARY " + CHR$(34) + "..." + CHR$(34): GOTO errmes













                    'convert '\\' to '\'
                    WHILE INSTR(x$, "\\")
                        z = INSTR(x$, "\\")
                        x$ = LEFT$(x$, z - 1) + RIGHT$(x$, LEN(x$) - z)
                    WEND

                    autoformat_x$ = x$ 'used for autolayout purposes

                    'Remove version number from library name
                    'Eg. libname:1.0 becomes libname <-> 1.0 which later becomes libname.so.1.0
                    v$ = ""
                    striplibver:
                    FOR z = LEN(x$) TO 1 STEP -1
                        a = ASC(x$, z)
                        IF a = _ASC_BACKSLASH OR a = _ASC_FORWARDSLASH THEN EXIT FOR
                        IF a = _ASC_FULLSTOP OR a = _ASC_COLON THEN
                            IF isuinteger(RIGHT$(x$, LEN(x$) - z)) THEN
                                IF LEN(v$) THEN v$ = RIGHT$(x$, LEN(x$) - z) + "." + v$ ELSE v$ = RIGHT$(x$, LEN(x$) - z)
                                x$ = LEFT$(x$, z - 1)
                                IF a = _ASC_COLON THEN EXIT FOR
                                GOTO striplibver
                            ELSE
                                EXIT FOR
                            END IF
                        END IF
                    NEXT
                    libver$ = v$


                    IF os$ = "WIN" THEN
                        'convert forward-slashes to back-slashes
                        DO WHILE INSTR(x$, "/")
                            z = INSTR(x$, "/")
                            x$ = LEFT$(x$, z - 1) + "\" + RIGHT$(x$, LEN(x$) - z)
                        LOOP
                    END IF

                    IF os$ = "LNX" THEN
                        'convert any back-slashes to forward-slashes
                        DO WHILE INSTR(x$, "\")
                            z = INSTR(x$, "\")
                            x$ = LEFT$(x$, z - 1) + "/" + RIGHT$(x$, LEN(x$) - z)
                        LOOP
                    END IF

                    'Separate path from name
                    libpath$ = ""
                    FOR z = LEN(x$) TO 1 STEP -1
                        a = ASC(x$, z)
                        IF a = 47 OR a = 92 THEN '\ or /
                            libpath$ = LEFT$(x$, z)
                            x$ = RIGHT$(x$, LEN(x$) - z)
                            EXIT FOR
                        END IF
                    NEXT

                    og_libpath$ = libpath$ ' save the original libpath

                    'Accept ./ and .\ as a reference to the source file
                    'folder, replacing it with the actual full path, if available
                    IF libpath$ = "./" OR libpath$ = ".\" THEN
                        libpath$ = ""
                        IF NoIDEMode THEN
                            libpath$ = FixDirectoryName(path.source$)
                        ELSE
                            IF LEN(ideprogname) THEN libpath$ = idepath$ + pathsep$
                        END IF
                    END IF

                    'Create a path which can be used for inline code (uses \\ instead of \)
                    libpath_inline$ = GetEscapedPath(libpath$)

                    IF LEN(x$) THEN
                        IF dynamiclibrary = 0 THEN
                            'Static library

                            IF os$ = "WIN" THEN
                                'check for .lib
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS(libpath$ + x$ + ".lib") THEN
                                        libname$ = libpath$ + x$ + ".lib"
                                        inlinelibname$ = libpath_inline$ + x$ + ".lib"
                                    END IF
                                END IF
                                'check for .a
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS(libpath$ + x$ + ".a") THEN
                                        libname$ = libpath$ + x$ + ".a"
                                        inlinelibname$ = libpath_inline$ + x$ + ".a"
                                    END IF
                                END IF
                                'check for .o
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS(libpath$ + x$ + ".o") THEN
                                        libname$ = libpath$ + x$ + ".o"
                                        inlinelibname$ = libpath_inline$ + x$ + ".o"
                                    END IF
                                END IF
                                'check for .lib
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS(x$ + ".lib") THEN
                                        libname$ = x$ + ".lib"
                                        inlinelibname$ = x$ + ".lib"
                                    END IF
                                END IF
                                'check for .a
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS(x$ + ".a") THEN
                                        libname$ = x$ + ".a"
                                        inlinelibname$ = x$ + ".a"
                                    END IF
                                END IF
                                'check for .o
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS(x$ + ".o") THEN
                                        libname$ = x$ + ".o"
                                        inlinelibname$ = x$ + ".o"
                                    END IF
                                END IF
                            END IF 'Windows

                            IF os$ = "LNX" THEN
                                IF staticlinkedlibrary = 0 THEN

                                    IF MacOSX THEN 'dylib support
                                        'check for .dylib (direct)
                                        IF LEN(libname$) = 0 THEN
                                            IF _FILEEXISTS(libpath$ + "lib" + x$ + "." + libver$ + ".dylib") THEN
                                                libname$ = libpath$ + "lib" + x$ + "." + libver$ + ".dylib"
                                                inlinelibname$ = libpath_inline$ + "lib" + x$ + "." + libver$ + ".dylib"
                                                IF LEN(libpath$) THEN mylibopt$ = mylibopt$ + " -Wl,-rpath " + libpath$ + " " ELSE mylibopt$ = mylibopt$ + " -Wl,-rpath ./ "
                                            END IF
                                        END IF
                                        IF LEN(libname$) = 0 THEN
                                            IF _FILEEXISTS(libpath$ + "lib" + x$ + ".dylib") THEN
                                                libname$ = libpath$ + "lib" + x$ + ".dylib"
                                                inlinelibname$ = libpath_inline$ + "lib" + x$ + ".dylib"
                                                IF LEN(libpath$) THEN mylibopt$ = mylibopt$ + " -Wl,-rpath " + libpath$ + " " ELSE mylibopt$ = mylibopt$ + " -Wl,-rpath ./ "
                                            END IF
                                        END IF
                                    END IF

                                    'check for .so (direct)
                                    IF LEN(libname$) = 0 THEN
                                        IF _FILEEXISTS(libpath$ + "lib" + x$ + ".so." + libver$) THEN
                                            libname$ = libpath$ + "lib" + x$ + ".so." + libver$
                                            inlinelibname$ = libpath_inline$ + "lib" + x$ + ".so." + libver$
                                            IF LEN(libpath$) THEN mylibopt$ = mylibopt$ + " -Wl,-rpath " + libpath$ + " " ELSE mylibopt$ = mylibopt$ + " -Wl,-rpath ./ "
                                        END IF
                                    END IF
                                    IF LEN(libname$) = 0 THEN
                                        IF _FILEEXISTS(libpath$ + "lib" + x$ + ".so") THEN
                                            libname$ = libpath$ + "lib" + x$ + ".so"
                                            inlinelibname$ = libpath_inline$ + "lib" + x$ + ".so"
                                            IF LEN(libpath$) THEN mylibopt$ = mylibopt$ + " -Wl,-rpath " + libpath$ + " " ELSE mylibopt$ = mylibopt$ + " -Wl,-rpath ./ "
                                        END IF
                                    END IF
                                END IF
                                'check for .a (direct)
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS(libpath$ + "lib" + x$ + ".a") THEN
                                        libname$ = libpath$ + "lib" + x$ + ".a"
                                        inlinelibname$ = libpath_inline$ + "lib" + x$ + ".a"
                                    END IF
                                END IF
                                'check for .o (direct)
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS(libpath$ + "lib" + x$ + ".o") THEN
                                        libname$ = libpath$ + "lib" + x$ + ".o"
                                        inlinelibname$ = libpath_inline$ + "lib" + x$ + ".o"
                                    END IF
                                END IF
                                IF staticlinkedlibrary = 0 THEN
                                    'check for .so (usr/lib64)
                                    IF LEN(libname$) = 0 THEN
                                        IF _FILEEXISTS("/usr/lib64/" + libpath$ + "lib" + x$ + ".so." + libver$) THEN
                                            libname$ = "/usr/lib64/" + libpath$ + "lib" + x$ + ".so." + libver$
                                            inlinelibname$ = "/usr/lib64/" + libpath_inline$ + "lib" + x$ + ".so." + libver$
                                            IF LEN(libpath$) THEN mylibopt$ = mylibopt$ + " -Wl,-rpath /usr/lib64/" + libpath$ + " " ELSE mylibopt$ = mylibopt$ + " -Wl,-rpath /usr/lib64/ "
                                        END IF
                                    END IF
                                    IF LEN(libname$) = 0 THEN
                                        IF _FILEEXISTS("/usr/lib64/" + libpath$ + "lib" + x$ + ".so") THEN
                                            libname$ = "/usr/lib64/" + libpath$ + "lib" + x$ + ".so"
                                            inlinelibname$ = "/usr/lib64/" + libpath_inline$ + "lib" + x$ + ".so"
                                            IF LEN(libpath$) THEN mylibopt$ = mylibopt$ + " -Wl,-rpath /usr/lib64/" + libpath$ + " " ELSE mylibopt$ = mylibopt$ + " -Wl,-rpath /usr/lib64/ "
                                        END IF
                                    END IF
                                END IF
                                'check for .a (usr/lib64)
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS("/usr/lib64/" + libpath$ + "lib" + x$ + ".a") THEN
                                        libname$ = "/usr/lib64/" + libpath$ + "lib" + x$ + ".a"
                                        inlinelibname$ = "/usr/lib64/" + libpath_inline$ + "lib" + x$ + ".a"
                                    END IF
                                END IF
                                IF staticlinkedlibrary = 0 THEN

                                    IF MacOSX THEN 'dylib support
                                        'check for .dylib (usr/lib)
                                        IF LEN(libname$) = 0 THEN
                                            IF _FILEEXISTS("/usr/lib/" + libpath$ + "lib" + x$ + "." + libver$ + ".dylib") THEN
                                                libname$ = "/usr/lib/" + libpath$ + "lib" + x$ + "." + libver$ + ".dylib"
                                                inlinelibname$ = "/usr/lib/" + libpath_inline$ + "lib" + x$ + "." + libver$ + ".dylib"
                                                IF LEN(libpath$) THEN mylibopt$ = mylibopt$ + " -Wl,-rpath /usr/lib/" + libpath$ + " " ELSE mylibopt$ = mylibopt$ + " -Wl,-rpath /usr/lib/ "
                                            END IF
                                        END IF
                                        IF LEN(libname$) = 0 THEN
                                            IF _FILEEXISTS("/usr/lib/" + libpath$ + "lib" + x$ + ".dylib") THEN
                                                libname$ = "/usr/lib/" + libpath$ + "lib" + x$ + ".dylib"
                                                inlinelibname$ = "/usr/lib/" + libpath_inline$ + "lib" + x$ + ".dylib"
                                                IF LEN(libpath$) THEN mylibopt$ = mylibopt$ + " -Wl,-rpath /usr/lib/" + libpath$ + " " ELSE mylibopt$ = mylibopt$ + " -Wl,-rpath /usr/lib/ "
                                            END IF
                                        END IF
                                    END IF

                                    'check for .so (usr/lib)
                                    IF LEN(libname$) = 0 THEN
                                        IF _FILEEXISTS("/usr/lib/" + libpath$ + "lib" + x$ + ".so." + libver$) THEN
                                            libname$ = "/usr/lib/" + libpath$ + "lib" + x$ + ".so." + libver$
                                            inlinelibname$ = "/usr/lib/" + libpath_inline$ + "lib" + x$ + ".so." + libver$
                                            IF LEN(libpath$) THEN mylibopt$ = mylibopt$ + " -Wl,-rpath /usr/lib/" + libpath$ + " " ELSE mylibopt$ = mylibopt$ + " -Wl,-rpath /usr/lib/ "
                                        END IF
                                    END IF
                                    IF LEN(libname$) = 0 THEN
                                        IF _FILEEXISTS("/usr/lib/" + libpath$ + "lib" + x$ + ".so") THEN
                                            libname$ = "/usr/lib/" + libpath$ + "lib" + x$ + ".so"
                                            inlinelibname$ = "/usr/lib/" + libpath_inline$ + "lib" + x$ + ".so"
                                            IF LEN(libpath$) THEN mylibopt$ = mylibopt$ + " -Wl,-rpath /usr/lib/" + libpath$ + " " ELSE mylibopt$ = mylibopt$ + " -Wl,-rpath /usr/lib/ "
                                        END IF
                                    END IF
                                END IF
                                'check for .a (usr/lib)
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS("/usr/lib/" + libpath$ + "lib" + x$ + ".a") THEN
                                        libname$ = "/usr/lib/" + libpath$ + "lib" + x$ + ".a"
                                        inlinelibname$ = "/usr/lib/" + libpath_inline$ + "lib" + x$ + ".a"
                                    END IF
                                END IF
                                '--------------------------(without path)------------------------------
                                IF staticlinkedlibrary = 0 THEN

                                    IF MacOSX THEN 'dylib support
                                        'check for .dylib (direct)
                                        IF LEN(libname$) = 0 THEN
                                            IF _FILEEXISTS("lib" + x$ + "." + libver$ + ".dylib") THEN
                                                libname$ = "lib" + x$ + "." + libver$ + ".dylib"
                                                inlinelibname$ = "lib" + x$ + "." + libver$ + ".dylib"
                                                mylibopt$ = mylibopt$ + " -Wl,-rpath ./ "
                                            END IF
                                        END IF
                                        IF LEN(libname$) = 0 THEN
                                            IF _FILEEXISTS("lib" + x$ + ".dylib") THEN
                                                libname$ = "lib" + x$ + ".dylib"
                                                inlinelibname$ = "lib" + x$ + ".dylib"
                                                mylibopt$ = mylibopt$ + " -Wl,-rpath ./ "
                                            END IF
                                        END IF
                                    END IF

                                    'check for .so (direct)
                                    IF LEN(libname$) = 0 THEN
                                        IF _FILEEXISTS("lib" + x$ + ".so." + libver$) THEN
                                            libname$ = "lib" + x$ + ".so." + libver$
                                            inlinelibname$ = "lib" + x$ + ".so." + libver$
                                            mylibopt$ = mylibopt$ + " -Wl,-rpath ./ "
                                        END IF
                                    END IF
                                    IF LEN(libname$) = 0 THEN
                                        IF _FILEEXISTS("lib" + x$ + ".so") THEN
                                            libname$ = "lib" + x$ + ".so"
                                            inlinelibname$ = "lib" + x$ + ".so"
                                            mylibopt$ = mylibopt$ + " -Wl,-rpath ./ "
                                        END IF
                                    END IF
                                END IF
                                'check for .a (direct)
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS("lib" + x$ + ".a") THEN
                                        libname$ = "lib" + x$ + ".a"
                                        inlinelibname$ = "lib" + x$ + ".a"
                                    END IF
                                END IF
                                'check for .o (direct)
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS("lib" + x$ + ".o") THEN
                                        libname$ = "lib" + x$ + ".o"
                                        inlinelibname$ = "lib" + x$ + ".o"
                                    END IF
                                END IF
                                IF staticlinkedlibrary = 0 THEN
                                    'check for .so (usr/lib64)
                                    IF LEN(libname$) = 0 THEN
                                        IF _FILEEXISTS("/usr/lib64/" + "lib" + x$ + ".so." + libver$) THEN
                                            libname$ = "/usr/lib64/" + "lib" + x$ + ".so." + libver$
                                            inlinelibname$ = "/usr/lib64/" + "lib" + x$ + ".so." + libver$
                                            mylibopt$ = mylibopt$ + " -Wl,-rpath /usr/lib64/ "
                                        END IF
                                    END IF
                                    IF LEN(libname$) = 0 THEN
                                        IF _FILEEXISTS("/usr/lib64/" + "lib" + x$ + ".so") THEN
                                            libname$ = "/usr/lib64/" + "lib" + x$ + ".so"
                                            inlinelibname$ = "/usr/lib64/" + "lib" + x$ + ".so"
                                            mylibopt$ = mylibopt$ + " -Wl,-rpath /usr/lib64/ "
                                        END IF
                                    END IF
                                END IF
                                'check for .a (usr/lib64)
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS("/usr/lib64/" + "lib" + x$ + ".a") THEN
                                        libname$ = "/usr/lib64/" + "lib" + x$ + ".a"
                                        inlinelibname$ = "/usr/lib64/" + "lib" + x$ + ".a"
                                    END IF
                                END IF
                                IF staticlinkedlibrary = 0 THEN

                                    IF MacOSX THEN 'dylib support
                                        'check for .dylib (usr/lib)
                                        IF LEN(libname$) = 0 THEN
                                            IF _FILEEXISTS("/usr/lib/" + "lib" + x$ + "." + libver$ + ".dylib") THEN
                                                libname$ = "/usr/lib/" + "lib" + x$ + "." + libver$ + ".dylib"
                                                inlinelibname$ = "/usr/lib/" + "lib" + x$ + "." + libver$ + ".dylib"
                                            END IF
                                        END IF
                                        IF LEN(libname$) = 0 THEN
                                            IF _FILEEXISTS("/usr/lib/" + "lib" + x$ + ".dylib") THEN
                                                libname$ = "/usr/lib/" + "lib" + x$ + ".dylib"
                                                inlinelibname$ = "/usr/lib/" + "lib" + x$ + ".dylib"
                                                mylibopt$ = mylibopt$ + " -Wl,-rpath /usr/lib/ "
                                            END IF
                                        END IF
                                    END IF

                                    'check for .so (usr/lib)
                                    IF LEN(libname$) = 0 THEN
                                        IF _FILEEXISTS("/usr/lib/" + "lib" + x$ + ".so." + libver$) THEN
                                            libname$ = "/usr/lib/" + "lib" + x$ + ".so." + libver$
                                            inlinelibname$ = "/usr/lib/" + "lib" + x$ + ".so." + libver$
                                        END IF
                                    END IF
                                    IF LEN(libname$) = 0 THEN
                                        IF _FILEEXISTS("/usr/lib/" + "lib" + x$ + ".so") THEN
                                            libname$ = "/usr/lib/" + "lib" + x$ + ".so"
                                            inlinelibname$ = "/usr/lib/" + "lib" + x$ + ".so"
                                            mylibopt$ = mylibopt$ + " -Wl,-rpath /usr/lib/ "
                                        END IF
                                    END IF
                                END IF
                                'check for .a (usr/lib)
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS("/usr/lib/" + "lib" + x$ + ".a") THEN
                                        libname$ = "/usr/lib/" + "lib" + x$ + ".a"
                                        inlinelibname$ = "/usr/lib/" + "lib" + x$ + ".a"
                                        mylibopt$ = mylibopt$ + " -Wl,-rpath /usr/lib/ "
                                    END IF
                                END IF
                            END IF 'Linux


                            'check for header
                            IF LEN(headername$) = 0 THEN
                                IF os$ = "WIN" THEN
                                    IF _FILEEXISTS(libpath$ + x$ + ".h") THEN
                                        headername$ = libpath_inline$ + x$ + ".h"
                                        IF customtypelibrary = 0 THEN sfdeclare = 0
                                        sfheader = 1
                                        GOTO GotHeader
                                    END IF
                                    IF _FILEEXISTS(libpath$ + x$ + ".hpp") THEN
                                        headername$ = libpath_inline$ + x$ + ".hpp"
                                        IF customtypelibrary = 0 THEN sfdeclare = 0
                                        sfheader = 1
                                        GOTO GotHeader
                                    END IF
                                    '--------------------------(without path)------------------------------
                                    IF _FILEEXISTS(x$ + ".h") THEN
                                        headername$ = x$ + ".h"
                                        IF customtypelibrary = 0 THEN sfdeclare = 0
                                        sfheader = 1
                                        GOTO GotHeader
                                    END IF
                                    IF _FILEEXISTS(x$ + ".hpp") THEN
                                        headername$ = x$ + ".hpp"
                                        IF customtypelibrary = 0 THEN sfdeclare = 0
                                        sfheader = 1
                                        GOTO GotHeader
                                    END IF

                                    ' Fallback to source path
                                    IF inclevel > 0 THEN
                                        libpath$ = getfilepath(incname$(inclevel)) + og_libpath$
                                    ELSEIF NoIDEMode THEN
                                        libpath$ = FixDirectoryName(path.source$) + og_libpath$
                                    ELSE
                                        IF LEN(ideprogname) THEN libpath$ = idepath$ + pathsep$ + og_libpath$
                                    END IF
                                    libpath_inline$ = GetEscapedPath(libpath$)
                                    IF _FILEEXISTS(libpath$ + x$ + ".h") THEN
                                        headername$ = libpath_inline$ + x$ + ".h"
                                        IF customtypelibrary = 0 THEN sfdeclare = 0
                                        sfheader = 1
                                        GOTO GotHeader
                                    END IF
                                    IF _FILEEXISTS(libpath$ + x$ + ".hpp") THEN
                                        headername$ = libpath_inline$ + x$ + ".hpp"
                                        IF customtypelibrary = 0 THEN sfdeclare = 0
                                        sfheader = 1
                                        GOTO GotHeader
                                    END IF
                                END IF 'Windows

                                IF os$ = "LNX" THEN
                                    IF _FILEEXISTS(libpath$ + x$ + ".h") THEN
                                        headername$ = libpath_inline$ + x$ + ".h"
                                        IF customtypelibrary = 0 THEN sfdeclare = 0
                                        sfheader = 1
                                        GOTO GotHeader
                                    END IF
                                    IF _FILEEXISTS(libpath$ + x$ + ".hpp") THEN
                                        headername$ = libpath_inline$ + x$ + ".hpp"
                                        IF customtypelibrary = 0 THEN sfdeclare = 0
                                        sfheader = 1
                                        GOTO GotHeader
                                    END IF
                                    IF _FILEEXISTS("/usr/include/" + libpath$ + x$ + ".h") THEN
                                        headername$ = "/usr/include/" + libpath_inline$ + x$ + ".h"
                                        IF customtypelibrary = 0 THEN sfdeclare = 0
                                        sfheader = 1
                                        GOTO GotHeader
                                    END IF
                                    IF _FILEEXISTS("/usr/include/" + libpath$ + x$ + ".hpp") THEN
                                        headername$ = "/usr/include/" + libpath_inline$ + x$ + ".hpp"
                                        IF customtypelibrary = 0 THEN sfdeclare = 0
                                        sfheader = 1
                                        GOTO GotHeader
                                    END IF
                                    '--------------------------(without path)------------------------------
                                    IF _FILEEXISTS(x$ + ".h") THEN
                                        headername$ = x$ + ".h"
                                        IF customtypelibrary = 0 THEN sfdeclare = 0
                                        sfheader = 1
                                        GOTO GotHeader
                                    END IF
                                    IF _FILEEXISTS(x$ + ".hpp") THEN
                                        headername$ = x$ + ".hpp"
                                        IF customtypelibrary = 0 THEN sfdeclare = 0
                                        sfheader = 1
                                        GOTO GotHeader
                                    END IF
                                    IF _FILEEXISTS("/usr/include/" + x$ + ".h") THEN
                                        headername$ = "/usr/include/" + x$ + ".h"
                                        IF customtypelibrary = 0 THEN sfdeclare = 0
                                        sfheader = 1
                                        GOTO GotHeader
                                    END IF
                                    IF _FILEEXISTS("/usr/include/" + x$ + ".hpp") THEN
                                        headername$ = "/usr/include/" + x$ + ".hpp"
                                        IF customtypelibrary = 0 THEN sfdeclare = 0
                                        sfheader = 1
                                        GOTO GotHeader
                                    END IF

                                    ' Fallback to source path
                                    IF inclevel > 0 THEN
                                        libpath$ = getfilepath(incname$(inclevel)) + og_libpath$
                                    ELSEIF NoIDEMode THEN
                                        libpath$ = FixDirectoryName(path.source$) + og_libpath$
                                    ELSE
                                        IF LEN(ideprogname) THEN libpath$ = idepath$ + pathsep$ + og_libpath$
                                    END IF
                                    libpath_inline$ = GetEscapedPath(libpath$)
                                    IF _FILEEXISTS(libpath$ + x$ + ".h") THEN
                                        headername$ = libpath_inline$ + x$ + ".h"
                                        IF customtypelibrary = 0 THEN sfdeclare = 0
                                        sfheader = 1
                                        GOTO GotHeader
                                    END IF
                                    IF _FILEEXISTS(libpath$ + x$ + ".hpp") THEN
                                        headername$ = libpath_inline$ + x$ + ".hpp"
                                        IF customtypelibrary = 0 THEN sfdeclare = 0
                                        sfheader = 1
                                        GOTO GotHeader
                                    END IF
                                END IF 'Linux

                                GotHeader:
                            END IF

                        ELSE
                            'dynamic library

                            IF os$ = "WIN" THEN
                                'check for .dll (direct)
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS(libpath$ + x$ + ".dll") THEN
                                        libname$ = libpath$ + x$ + ".dll"
                                        inlinelibname$ = libpath_inline$ + x$ + ".dll"
                                    END IF
                                END IF
                                'check for .dll (system32)
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS(ENVIRON$("SYSTEMROOT") + "\System32\" + libpath$ + x$ + ".dll") THEN
                                        libname$ = libpath$ + x$ + ".dll"
                                        inlinelibname$ = libpath_inline$ + x$ + ".dll"
                                    END IF
                                END IF
                                '--------------------------(without path)------------------------------
                                'check for .dll (direct)
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS(x$ + ".dll") OR _FILEEXISTS(FixDirectoryName(path.source$) + x$ + ".dll") OR _FILEEXISTS(FixDirectoryName(idepath$) + x$ + ".dll") THEN
                                        libname$ = x$ + ".dll"
                                        inlinelibname$ = x$ + ".dll"
                                    END IF
                                END IF
                                'check for .dll (system32)
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS(ENVIRON$("SYSTEMROOT") + "\System32\" + x$ + ".dll") THEN
                                        libname$ = x$ + ".dll"
                                        inlinelibname$ = x$ + ".dll"
                                    END IF
                                END IF
                            END IF 'Windows

                            IF os$ = "LNX" THEN
                                'Note: STATIC libraries (.a/.o) cannot be loaded as dynamic objects


                                IF MacOSX THEN 'dylib support
                                    'check for .dylib (direct)
                                    IF LEN(libname$) = 0 THEN
                                        IF _FILEEXISTS(libpath$ + "lib" + x$ + "." + libver$ + ".dylib") THEN
                                            libname$ = libpath$ + "lib" + x$ + "." + libver$ + ".dylib"
                                            inlinelibname$ = libpath_inline$ + "lib" + x$ + "." + libver$ + ".dylib"
                                            IF LEFT$(libpath$, 1) <> "/" THEN libname$ = "./" + libname$: inlinelibname$ = "./" + inlinelibname$
                                        END IF
                                    END IF
                                    IF LEN(libname$) = 0 THEN
                                        IF _FILEEXISTS(libpath$ + "lib" + x$ + ".dylib") THEN
                                            libname$ = libpath$ + "lib" + x$ + ".dylib"
                                            inlinelibname$ = libpath_inline$ + "lib" + x$ + ".dylib"
                                            IF LEFT$(libpath$, 1) <> "/" THEN libname$ = "./" + libname$: inlinelibname$ = "./" + inlinelibname$
                                        END IF
                                    END IF
                                END IF

                                'check for .so (direct)
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS(libpath$ + "lib" + x$ + ".so." + libver$) THEN
                                        libname$ = libpath$ + "lib" + x$ + ".so." + libver$
                                        inlinelibname$ = libpath_inline$ + "lib" + x$ + ".so." + libver$
                                        IF LEFT$(libpath$, 1) <> "/" THEN libname$ = "./" + libname$: inlinelibname$ = "./" + inlinelibname$
                                    END IF
                                END IF
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS(libpath$ + "lib" + x$ + ".so") THEN
                                        libname$ = libpath$ + "lib" + x$ + ".so"
                                        inlinelibname$ = libpath_inline$ + "lib" + x$ + ".so"
                                        IF LEFT$(libpath$, 1) <> "/" THEN libname$ = "./" + libname$: inlinelibname$ = "./" + inlinelibname$
                                    END IF
                                END IF
                                'check for .so (usr/lib64)
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS("/usr/lib64/" + libpath$ + "lib" + x$ + ".so." + libver$) THEN
                                        libname$ = "/usr/lib64/" + libpath$ + "lib" + x$ + ".so." + libver$
                                        inlinelibname$ = "/usr/lib64/" + libpath_inline$ + "lib" + x$ + ".so." + libver$
                                    END IF
                                END IF
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS("/usr/lib64/" + libpath$ + "lib" + x$ + ".so") THEN
                                        libname$ = "/usr/lib64/" + libpath$ + "lib" + x$ + ".so"
                                        inlinelibname$ = "/usr/lib64/" + libpath_inline$ + "lib" + x$ + ".so"
                                    END IF
                                END IF

                                IF MacOSX THEN 'dylib support
                                    'check for .dylib (usr/lib)
                                    IF LEN(libname$) = 0 THEN
                                        IF _FILEEXISTS("/usr/lib/" + libpath$ + "lib" + x$ + "." + libver$ + ".dylib") THEN
                                            libname$ = "/usr/lib/" + libpath$ + "lib" + x$ + "." + libver$ + ".dylib"
                                            inlinelibname$ = "/usr/lib/" + libpath_inline$ + "lib" + x$ + "." + libver$ + ".dylib"
                                        END IF
                                    END IF
                                    IF LEN(libname$) = 0 THEN
                                        IF _FILEEXISTS("/usr/lib/" + libpath$ + "lib" + x$ + ".dylib") THEN
                                            libname$ = "/usr/lib/" + libpath$ + "lib" + x$ + ".dylib"
                                            inlinelibname$ = "/usr/lib/" + libpath_inline$ + "lib" + x$ + ".dylib"
                                        END IF
                                    END IF
                                END IF

                                'check for .so (usr/lib)
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS("/usr/lib/" + libpath$ + "lib" + x$ + ".so." + libver$) THEN
                                        libname$ = "/usr/lib/" + libpath$ + "lib" + x$ + ".so." + libver$
                                        inlinelibname$ = "/usr/lib/" + libpath_inline$ + "lib" + x$ + ".so." + libver$
                                    END IF
                                END IF
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS("/usr/lib/" + libpath$ + "lib" + x$ + ".so") THEN
                                        libname$ = "/usr/lib/" + libpath$ + "lib" + x$ + ".so"
                                        inlinelibname$ = "/usr/lib/" + libpath_inline$ + "lib" + x$ + ".so"
                                    END IF
                                END IF
                                '--------------------------(without path)------------------------------
                                IF MacOSX THEN 'dylib support
                                    'check for .dylib (direct)
                                    IF LEN(libname$) = 0 THEN
                                        IF _FILEEXISTS("lib" + x$ + "." + libver$ + ".dylib") OR _FILEEXISTS(FixDirectoryName(path.source$) + "lib" + x$ + "." + libver$ + ".dylib") OR _FILEEXISTS(FixDirectoryName(idepath$) + "lib" + x$ + "." + libver$ + ".dylib") THEN
                                            libname$ = "lib" + x$ + "." + libver$ + ".dylib"
                                            inlinelibname$ = "lib" + x$ + "." + libver$ + ".dylib"
                                            libname$ = "./" + libname$: inlinelibname$ = "./" + inlinelibname$
                                        END IF
                                    END IF
                                    IF LEN(libname$) = 0 THEN
                                        IF _FILEEXISTS("lib" + x$ + ".dylib") OR _FILEEXISTS(FixDirectoryName(path.source$) + "lib" + x$ + ".dylib") OR _FILEEXISTS(FixDirectoryName(idepath$) + "lib" + x$ + ".dylib") THEN
                                            libname$ = "lib" + x$ + ".dylib"
                                            inlinelibname$ = "lib" + x$ + ".dylib"
                                            libname$ = "./" + libname$: inlinelibname$ = "./" + inlinelibname$
                                        END IF
                                    END IF
                                END IF

                                'check for .so (direct)
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS("lib" + x$ + ".so." + libver$) OR _FILEEXISTS(FixDirectoryName(path.source$) + "lib" + x$ + ".so." + libver$) OR _FILEEXISTS(FixDirectoryName(idepath$) + "lib" + x$ + ".so." + libver$) THEN
                                        libname$ = "lib" + x$ + ".so." + libver$
                                        inlinelibname$ = "lib" + x$ + ".so." + libver$
                                        libname$ = "./" + libname$: inlinelibname$ = "./" + inlinelibname$
                                    END IF
                                END IF
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS("lib" + x$ + ".so") OR _FILEEXISTS(FixDirectoryName(path.source$) + "lib" + x$ + ".so") OR _FILEEXISTS(FixDirectoryName(idepath$) + "lib" + x$ + ".so") THEN
                                        libname$ = "lib" + x$ + ".so"
                                        inlinelibname$ = "lib" + x$ + ".so"
                                        libname$ = "./" + libname$: inlinelibname$ = "./" + inlinelibname$
                                    END IF
                                END IF
                                'check for .so (usr/lib64)
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS("/usr/lib64/" + "lib" + x$ + ".so." + libver$) THEN
                                        libname$ = "/usr/lib64/" + "lib" + x$ + ".so." + libver$
                                        inlinelibname$ = "/usr/lib64/" + "lib" + x$ + ".so." + libver$
                                    END IF
                                END IF
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS("/usr/lib64/" + "lib" + x$ + ".so") THEN
                                        libname$ = "/usr/lib64/" + "lib" + x$ + ".so"
                                        inlinelibname$ = "/usr/lib64/" + "lib" + x$ + ".so"
                                    END IF
                                END IF

                                IF MacOSX THEN 'dylib support
                                    'check for .dylib (usr/lib)
                                    IF LEN(libname$) = 0 THEN
                                        IF _FILEEXISTS("/usr/lib/" + "lib" + x$ + "." + libver$ + ".dylib") THEN
                                            libname$ = "/usr/lib/" + "lib" + x$ + "." + libver$ + ".dylib"
                                            inlinelibname$ = "/usr/lib/" + "lib" + x$ + "." + libver$ + ".dylib"
                                        END IF
                                    END IF
                                    IF LEN(libname$) = 0 THEN
                                        IF _FILEEXISTS("/usr/lib/" + "lib" + x$ + ".dylib") THEN
                                            libname$ = "/usr/lib/" + "lib" + x$ + ".dylib"
                                            inlinelibname$ = "/usr/lib/" + "lib" + x$ + ".dylib"
                                        END IF
                                    END IF
                                END IF

                                'check for .so (usr/lib)
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS("/usr/lib/" + "lib" + x$ + ".so." + libver$) THEN
                                        libname$ = "/usr/lib/" + "lib" + x$ + ".so." + libver$
                                        inlinelibname$ = "/usr/lib/" + "lib" + x$ + ".so." + libver$
                                    END IF
                                END IF
                                IF LEN(libname$) = 0 THEN
                                    IF _FILEEXISTS("/usr/lib/" + "lib" + x$ + ".so") THEN
                                        libname$ = "/usr/lib/" + "lib" + x$ + ".so"
                                        inlinelibname$ = "/usr/lib/" + "lib" + x$ + ".so"
                                    END IF
                                END IF
                            END IF 'Linux

                        END IF 'Dynamic

                        'library found?
                        IF dynamiclibrary <> 0 AND LEN(libname$) = 0 THEN a$ = "DYNAMIC LIBRARY not found": GOTO errmes
                        IF LEN(libname$) = 0 AND LEN(headername$) = 0 THEN a$ = "LIBRARY not found": GOTO errmes

                        '***actual method should cull redundant header and library entries***

                        IF dynamiclibrary = 0 THEN

                            'static
                            IF LEN(libname$) THEN
                                IF os$ = "WIN" THEN
                                    IF MID$(libname$, 2, 1) = ":" OR LEFT$(libname$, 1) = "\" THEN
                                        mylib$ = mylib$ + " " + libname$ + " "
                                    ELSE
                                        mylib$ = mylib$ + " ..\..\" + libname$ + " "
                                    END IF
                                END IF
                                IF os$ = "LNX" THEN
                                    IF LEFT$(libname$, 1) = "/" THEN
                                        mylib$ = mylib$ + " " + libname$ + " "
                                    ELSE
                                        mylib$ = mylib$ + " ../../" + libname$ + " "
                                    END IF
                                END IF
                                IF _FILEEXISTS(libname$) THEN WriteBufLine ExtDepBuf, "DECL: " + _FULLPATH$(libname$)
                            END IF

                        ELSE

                            'dynamic
                            IF LEN(headername$) = 0 THEN 'no header

                                IF subfuncn THEN
                                    f = OpenBuffer%("A", tmpdir$ + "maindata.txt")
                                ELSE
                                    f = DataTxtBuf
                                END IF

                                'make name a C-appropriate variable name
                                'by converting everything except numbers and
                                'letters to underscores
                                x2$ = x$
                                FOR x2 = 1 TO LEN(x2$)
                                    IF ASC(x2$, x2) < 48 THEN ASC(x2$, x2) = 95
                                    IF ASC(x2$, x2) > 57 AND ASC(x2$, x2) < 65 THEN ASC(x2$, x2) = 95
                                    IF ASC(x2$, x2) > 90 AND ASC(x2$, x2) < 97 THEN ASC(x2$, x2) = 95
                                    IF ASC(x2$, x2) > 122 THEN ASC(x2$, x2) = 95
                                NEXT
                                DLLname$ = x2$
                                IF _FILEEXISTS(libname$) THEN WriteBufLine ExtDepBuf, "DECL: " + _FULLPATH$(libname$)

                                IF sfdeclare THEN

                                    'Dynamic libraries are loaded during generated initialization code,
                                    'before normal BASIC statement tracking can identify the declaration.
                                    'Record the DECLARE line only on loader failure, avoiding stale locations
                                    'after a successful load.
                                    errortrackcall$ = ""
                                    IF GetRCStateVar(ErrorLocationMode) = 2 THEN
                                        IF inclinenumber(inclevel) THEN
                                            thisincname$ = getfilepath$(incname$(inclevel))
                                            thisincname$ = MID$(incname$(inclevel), LEN(thisincname$) + 1)
                                            errortrackcall$ = "error_track_line(" + _TOSTR$(linenumber) + "," + _TOSTR$(inclinenumber(inclevel)) + "," + CHR$(34) + thisincname$ + CHR$(34) + ");"
                                        ELSE
                                            errortrackcall$ = "error_track_line(" + _TOSTR$(linenumber) + ",0,NULL);"
                                        END IF
                                    END IF

                                    IF os$ = "WIN" THEN
                                        WriteBufLine RegTxtBuf, "HINSTANCE DLL_" + x2$ + "=NULL;"
                                        WriteBufLine f, "if (!DLL_" + x2$ + "){"
                                        WriteBufLine f, "DLL_" + x2$ + "=LoadLibrary(" + CHR$(34) + inlinelibname$ + CHR$(34) + ");"
                                        WriteBufLine f, "if (!DLL_" + x2$ + "){" + errortrackcall$ + "error(259);}"
                                        WriteBufLine f, "}"
                                    END IF

                                    IF os$ = "LNX" THEN
                                        WriteBufLine RegTxtBuf, "void *DLL_" + x2$ + "=NULL;"
                                        WriteBufLine f, "if (!DLL_" + x2$ + "){"
                                        WriteBufLine f, "DLL_" + x2$ + "=dlopen(" + CHR$(34) + inlinelibname$ + CHR$(34) + ",RTLD_LAZY);"
                                        WriteBufLine f, "if (!DLL_" + x2$ + "){" + errortrackcall$ + "error(259);}"
                                        WriteBufLine f, "}"
                                    END IF

                                END IF

                            END IF 'no header

                        END IF 'dynamiclibrary

                        IF LEN(headername$) THEN
                            IF (os$ = "WIN" AND (MID$(headername$, 2, 1) = ":" OR LEFT$(headername$, 1) = "\")) _
                            OR (os$ = "LNX" AND (LEFT$(headername$, 1) = "/")) THEN
                                WriteBufLine RegTxtBuf, "#include " + CHR$(34) + headername$ + CHR$(34)
                            ELSE
                                WriteBufLine RegTxtBuf, "#include " + CHR$(34) + "../../" + headername$ + CHR$(34)
                            END IF
                            IF _FILEEXISTS(headername$) THEN WriteBufLine ExtDepBuf, "DECL: " + _FULLPATH$(headername$)
                        END IF

                    END IF

                    l$ = l$ + sp + CHR$(34) + autoformat_x$ + CHR$(34)

                    IF n > x THEN
                        IF dynamiclibrary THEN a$ = "Cannot specify multiple DYNAMIC LIBRARY names in a single DECLARE statement": GOTO errmes
                        x = x + 1: x2$ = getelement$(a$, x): IF x2$ <> "," THEN a$ = "Expected ,": GOTO errmes
                        l$ = l$ + sp2 + ","
                        x = x + 1: IF x > n THEN a$ = "Expected , ...": GOTO errmes
                        GOTO addlibrary
                    END IF

                END IF 'n>=x

                layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                GOTO finishednonexec
            END IF

            GOTO finishednonexec 'note: no layout required
        END IF
    END IF

    'begin SUB/FUNCTION
    IF n >= 1 THEN
        dynamiclibrary = 0
        declaresubfunc2:
        sf = 0
        IF firstelement$ = "FUNCTION" THEN sf = 1
        IF firstelement$ = "SUB" THEN sf = 2
        IF sf THEN

            IF declaringlibrary = 0 THEN
                IF LEN(subfunc) THEN a$ = "Expected END SUB/FUNCTION before " + firstelement$: GOTO errmes
            END IF

            IF n = 1 THEN a$ = "Expected name after SUB/FUNCTION": GOTO errmes
            e$ = getelement$(ca$, 2)
            symbol$ = removesymbol$(e$) '$,%,etc.
            IF Error_Happened THEN GOTO errmes
            IF sf = 2 AND symbol$ <> "" THEN a$ = "Type symbols after a SUB name are invalid": GOTO errmes
            eOrig$ = e$: IF UCASE$(LEFT$(e$, 5)) = "_IKW_" THEN e$ = MID$(e$, 5)
            try = findid(e$)
            IF Error_Happened THEN GOTO errmes
            DO WHILE try
                IF id.subfunc = sf THEN GOTO createsf
                IF try = 2 THEN findanotherid = 1: try = findid(e$) ELSE try = 0
                IF Error_Happened THEN GOTO errmes
            LOOP
            a$ = "Unregistered SUB/FUNCTION encountered": GOTO errmes
            createsf:
            IF UCASE$(e$) = "_GL" THEN e$ = "_GL"
            IF firstelement$ = "SUB" THEN
                l$ = SCase$("Sub") + sp + eOrig$ + symbol$
            ELSE
                l$ = SCase$("Function") + sp + eOrig$ + symbol$
            END IF
            id2 = id
            targetid = currentid

            'check for ALIAS
            aliasname$ = RTRIM$(id.cn)
            IF n > 2 THEN
                ee$ = getelement$(a$, 3)
                IF ee$ = "ALIAS" THEN
                    IF declaringlibrary = 0 THEN a$ = "ALIAS can only be used with DECLARE LIBRARY": GOTO errmes
                    IF n = 3 THEN a$ = "Expected ALIAS name-in-library": GOTO errmes
                    ee$ = getelement$(ca$, 4)

                    'strip string content (optional)
                    IF LEFT$(ee$, 1) = CHR$(34) THEN
                        ee$ = RIGHT$(ee$, LEN(ee$) - 1)
                        x = INSTR(ee$, CHR$(34)): IF x = 0 THEN a$ = "Expected " + CHR$(34): GOTO errmes
                        ee$ = LEFT$(ee$, x - 1)
                        l$ = l$ + sp + SCase$("Alias") + sp + CHR_QUOTE + ee$ + CHR_QUOTE
                    ELSE
                        l$ = l$ + sp + SCase$("Alias") + sp + ee$
                    END IF

                    'strip fix046$ (created by unquoted periods)
                    DO WHILE INSTR(ee$, fix046$)
                        x = INSTR(ee$, fix046$): ee$ = LEFT$(ee$, x - 1) + "." + RIGHT$(ee$, LEN(ee$) - x + 1 - LEN(fix046$))
                    LOOP
                    aliasname$ = ee$
                    'remove ALIAS section from line
                    IF n <= 4 THEN a$ = getelements(a$, 1, 2)
                    IF n >= 5 THEN a$ = getelements(a$, 1, 2) + sp + getelements(a$, 5, n)
                    IF n <= 4 THEN ca$ = getelements(ca$, 1, 2)
                    IF n >= 5 THEN ca$ = getelements(ca$, 1, 2) + sp + getelements(ca$, 5, n)
                    n = n - 2
                END IF
            END IF

            IF declaringlibrary THEN GOTO declibjmp1

            'check for open controls (copy #2)
            IF controllevel <> 0 AND controltype(controllevel) <> 6 THEN 'It's OK for subs to be inside $IF blocks
                a$ = "Unidentified open control block"
                SELECT CASE controltype(controllevel)
                    CASE 1: a$ = "IF without END IF"
                    CASE 2: a$ = "FOR without NEXT"
                    CASE 3, 4: a$ = "DO without LOOP"
                    CASE 5: a$ = "WHILE without WEND"
                    CASE 10 TO 19: a$ = "SELECT CASE without END SELECT"
                END SELECT
                linenumber = controlref(controllevel)
                GOTO errmes
            END IF

            IF IDEIndentSubs THEN
                controllevel = controllevel + 1
                controltype(controllevel) = 32
                controlref(controllevel) = linenumber
            END IF

            subfunc = RTRIM$(id.callname) 'SUB_..."
            IF id.subfunc = 1 THEN subfuncoriginalname$ = "FUNCTION " ELSE subfuncoriginalname$ = "SUB "
            subfuncoriginalname$ = subfuncoriginalname$ + RTRIM$(id.cn)
            subfuncnlast = subfuncnlast + 1
            subfuncn = subfuncnlast
            subfuncid = targetid

            subfuncret$ = ""
            IF GetRCStateVar(vWatchOn) = 1 AND firstLineNumberLabelvWatch > 0 THEN
                vWatchAddLabel linenumber, -1
                closeMainVwatchSection
                firstLineNumberLabelvWatch = 0
            END IF

            MainTxtBuf = OpenBuffer%("O", tmpdir$ + "main" + _TOSTR$(subfuncn) + ".txt")
            DataTxtBuf = OpenBuffer%("O", tmpdir$ + "data" + _TOSTR$(subfuncn) + ".txt")
            FreeTxtBuf = OpenBuffer%("O", tmpdir$ + "free" + _TOSTR$(subfuncn) + ".txt")
            RetTxtBuf = OpenBuffer%("O", tmpdir$ + "ret" + _TOSTR$(subfuncn) + ".txt")
            defdatahandle = DataTxtBuf
            WriteBufLine RetTxtBuf, "if (next_return_point){"
            WriteBufLine RetTxtBuf, "next_return_point--;"
            WriteBufLine RetTxtBuf, "switch(return_point[next_return_point]){"
            WriteBufLine RetTxtBuf, "case 0:"
            WriteBufLine RetTxtBuf, "error(3);" 'return without gosub!
            WriteBufLine RetTxtBuf, "break;"

            declibjmp1:

            IF declaringlibrary THEN
                IF sfdeclare = 0 AND indirectlibrary = 0 THEN
                    RegTxtBuf = OpenBuffer%("O", tmpdir$ + "regsf_ignore.txt")
                END IF
                IF sfdeclare = 1 AND customtypelibrary = 0 AND dynamiclibrary = 0 AND indirectlibrary = 0 THEN
                    WriteBufLine RegTxtBuf, "#include " + CHR$(34) + "externtype" + _TOSTR$(ResolveStaticFunctions + 1) + ".txt" + CHR$(34)
                    fh = FREEFILE: OPEN tmpdir$ + "externtype" + _TOSTR$(ResolveStaticFunctions + 1) + ".txt" FOR OUTPUT AS #fh: CLOSE #fh
                END IF
            END IF




            IF sf = 1 THEN
                rettyp = id.ret
                t$ = typ2ctyp$(id.ret, "")
                IF Error_Happened THEN GOTO errmes
                IF t$ = "qbs" THEN t$ = "qbs*"

                IF declaringlibrary THEN
                    IF rettyp AND ISSTRING THEN
                        t$ = "char*"
                    END IF
                END IF

                IF declaringlibrary <> 0 AND dynamiclibrary <> 0 THEN
                    IF os$ = "WIN" THEN
                        WriteBufRawData RegTxtBuf, "typedef " + t$ + " (CALLBACK* DLLCALL_" + removecast$(RTRIM$(id.callname)) + ")("
                    END IF
                    IF os$ = "LNX" THEN
                        WriteBufRawData RegTxtBuf, "typedef " + t$ + " (*DLLCALL_" + removecast$(RTRIM$(id.callname)) + ")("
                    END IF
                ELSEIF declaringlibrary <> 0 AND customtypelibrary <> 0 THEN
                    WriteBufRawData RegTxtBuf, "typedef " + t$ + " CUSTOMCALL_" + removecast$(RTRIM$(id.callname)) + "("
                ELSE
                    WriteBufRawData RegTxtBuf, t$ + " " + removecast$(RTRIM$(id.callname)) + "("
                END IF
                IF declaringlibrary THEN GOTO declibjmp2
                WriteBufRawData MainTxtBuf, t$ + " " + removecast$(RTRIM$(id.callname)) + "("

                'create variable to return result
                'if type wasn't specified, define it
                IF symbol$ = "" THEN
                    a = ASC(UCASE$(e$)): IF a = 95 THEN a = 91
                    a = a - 64 'so A=1, Z=27 and _=28
                    symbol$ = defineextaz(a)
                END IF
                reginternalvariable = 1
                ignore = dim2(e$, symbol$, 0, "")
                IF Error_Happened THEN GOTO errmes
                reginternalvariable = 0
                'the following line stops the return variable from being free'd before being returned
                FreeTxtBuf = OpenBuffer%("O", tmpdir$ + "free" + _TOSTR$(subfuncn) + ".txt")
                'create return
                IF (rettyp AND ISSTRING) THEN
                    r$ = refer$(_TOSTR$(currentid), id.t, 1)
                    IF Error_Happened THEN GOTO errmes
                    subfuncret$ = subfuncret$ + "qbs_maketmp(" + r$ + ");"
                    subfuncret$ = subfuncret$ + "return " + r$ + ";"
                ELSE
                    r$ = refer$(_TOSTR$(currentid), id.t, 0)
                    IF Error_Happened THEN GOTO errmes
                    subfuncret$ = "return " + r$ + ";"
                END IF
            ELSE

                IF declaringlibrary <> 0 AND dynamiclibrary <> 0 THEN
                    IF os$ = "WIN" THEN
                        WriteBufRawData RegTxtBuf, "typedef void (CALLBACK* DLLCALL_" + removecast$(RTRIM$(id.callname)) + ")("
                    END IF
                    IF os$ = "LNX" THEN
                        WriteBufRawData RegTxtBuf, "typedef void (*DLLCALL_" + removecast$(RTRIM$(id.callname)) + ")("
                    END IF
                ELSEIF declaringlibrary <> 0 AND customtypelibrary <> 0 THEN
                    WriteBufRawData RegTxtBuf, "typedef void CUSTOMCALL_" + removecast$(RTRIM$(id.callname)) + "("
                ELSE
                    WriteBufRawData RegTxtBuf, "void " + removecast$(RTRIM$(id.callname)) + "("
                END IF
                IF declaringlibrary THEN GOTO declibjmp2
                WriteBufRawData MainTxtBuf, "void " + removecast$(RTRIM$(id.callname)) + "("
            END IF
            declibjmp2:

            addstatic2layout = 0
            staticsf = 0
            e$ = getelement$(a$, n)
            IF e$ = "STATIC" THEN
                IF declaringlibrary THEN a$ = "STATIC cannot be used in a library declaration": GOTO errmes
                addstatic2layout = 1
                staticsf = 2
                a$ = LEFT$(a$, LEN(a$) - 7): n = n - 1 'remove STATIC
            END IF

            'check items to pass
            params = 0
            AllowLocalName = 1
            IF n > 2 THEN
                e$ = getelement$(a$, 3)
                IF e$ <> "(" THEN a$ = "Expected (": GOTO errmes
                e$ = getelement$(a$, n)
                IF e$ <> ")" THEN a$ = "Expected )": GOTO errmes
                l$ = l$ + sp + "("
                IF n = 4 THEN GOTO nosfparams2
                IF n < 4 THEN a$ = "Expected ( ... )": GOTO errmes
                B = 0
                a2$ = ""
                FOR i = 4 TO n - 1
                    e$ = getelement$(ca$, i)
                    IF e$ = "(" THEN B = B + 1
                    IF e$ = ")" THEN B = B - 1
                    IF e$ = "," AND B = 0 THEN
                        IF i = n - 1 THEN a$ = "Expected , ... )": GOTO errmes
                        getlastparam2:
                        IF a2$ = "" THEN a$ = "Expected ... ,": GOTO errmes
                        a2$ = LEFT$(a2$, LEN(a2$) - 1)
                        'possible format: [BYVAL]a[%][(1)][AS][type]
                        params = params + 1
                        glinkid = targetid
                        glinkarg = params



                        IF params > 1 THEN
                            WriteBufRawData RegTxtBuf, ","

                            IF declaringlibrary = 0 THEN
                                WriteBufRawData MainTxtBuf, ","
                            END IF

                        END IF
                        n2 = numelements(a2$)
                        array = 0
                        t2$ = ""
                        e$ = getelement$(a2$, 1)

                        byvalue = 0
                        IF UCASE$(e$) = "BYVAL" THEN
                            IF declaringlibrary = 0 THEN a$ = "BYVAL can only be used with DECLARE LIBRARY": GOTO errmes
                            byvalue = 1: a2$ = RIGHT$(a2$, LEN(a2$) - 6)
                            IF RIGHT$(l$, 1) = "(" THEN l$ = l$ + sp2 + SCase$("ByVal") ELSE l$ = l$ + sp + SCase$("ByVal")
                            n2 = numelements(a2$): e$ = getelement$(a2$, 1)
                        END IF

                        IF RIGHT$(l$, 1) = "(" THEN l$ = l$ + sp2 + e$ ELSE l$ = l$ + sp + e$

                        n2$ = e$
                        dimmethod = 0


                        symbol2$ = removesymbol$(n2$)
                        IF validname(n2$) = 0 THEN a$ = "Invalid name": GOTO errmes

                        IF Error_Happened THEN GOTO errmes
                        IF symbol2$ <> "" THEN dimmethod = 1
                        m = 0
                        FOR i2 = 2 TO n2
                            e$ = getelement$(a2$, i2)
                            IF e$ = "(" THEN
                                IF m <> 0 THEN a$ = "Syntax error - too many opening brackets": GOTO errmes
                                m = 1
                                array = 1
                                l$ = l$ + sp2 + "("
                                GOTO gotaa2
                            END IF
                            IF e$ = ")" THEN
                                IF m <> 1 THEN a$ = "Syntax error - closing bracket without opening bracket": GOTO errmes
                                m = 2
                                l$ = l$ + sp2 + ")"
                                GOTO gotaa2
                            END IF
                            IF UCASE$(e$) = "AS" THEN
                                IF m <> 0 AND m <> 2 THEN a$ = "Syntax error - check your brackets": GOTO errmes
                                m = 3
                                l$ = l$ + sp + SCase$("As")
                                GOTO gotaa2
                            END IF
                            IF m = 1 THEN
                                IF declaringlibrary = 0 THEN a$ = "Array parameters require empty parentheses ()": GOTO errmes
                                l$ = l$ + sp + e$: GOTO gotaa2 'DECLARE LIBRARY keeps its legacy bracket contents
                            END IF
                            IF m <> 3 THEN a$ = "Syntax error - check your brackets": GOTO errmes
                            IF t2$ = "" THEN t2$ = e$ ELSE t2$ = t2$ + " " + e$
                            gotaa2:
                        NEXT i2
                        IF m = 1 THEN a$ = "Syntax error - check your brackets": GOTO errmes
                        IF symbol2$ <> "" AND t2$ <> "" THEN a$ = "Syntax error - check parameter types": GOTO errmes


                        IF LEN(t2$) THEN 'add type-name after AS
                            t2$ = UCASE$(t2$)
                            t3$ = t2$
                            typ = typname2typ(t3$)
                            IF Error_Happened THEN GOTO errmes
                            IF typ = 0 THEN a$ = "Undefined type": GOTO errmes
                            IF typ AND ISUDT THEN
                                t3$ = RTRIM$(udtxcname(typ AND UDTMASK))
                                l$ = l$ + sp + t3$
                            ELSE
                                FOR t3i = 1 TO LEN(t3$)
                                    IF ASC(t3$, t3i) = 32 THEN ASC(t3$, t3i) = ASC(sp)
                                NEXT
                                t3$ = SCase2$(t3$)
                                l$ = l$ + sp + t3$
                            END IF
                        END IF

                        IF t2$ = "" THEN t2$ = symbol2$
                        IF t2$ = "" THEN
                            IF LEFT$(n2$, 1) = "_" THEN v = 27 ELSE v = ASC(UCASE$(n2$)) - 64
                            t2$ = defineaz(v)
                            dimmethod = 1
                        END IF




                        IF array = 1 THEN
                            IF declaringlibrary THEN a$ = "Arrays cannot be passed to a library": GOTO errmes
                            dimsfarray = 1
                            'note: id2.nele is currently 0
                            nelereq = ASC(MID$(id2.nelereq, params, 1))
                            argdynmode = ASC(MID$(id2.dynudtargmode, params, 1))
                            IF argdynmode < 0 OR argdynmode > 1 THEN argdynmode = 0
                            IF nelereq THEN
                                nele = nelereq
                                MID$(id2.nele, params, 1) = CHR$(nele)

                                ids(targetid) = id2

                                sf_udt_dynmode = argdynmode
                                ignore = dim2(n2$, t2$, dimmethod, _TOSTR$(nele))
                                sf_udt_dynmode = 0
                                IF Error_Happened THEN GOTO errmes
                            ELSE
                                nele = 1
                                MID$(id2.nele, params, 1) = CHR$(nele)

                                ids(targetid) = id2

                                sf_udt_dynmode = argdynmode
                                ignore = dim2(n2$, t2$, dimmethod, "?")
                                sf_udt_dynmode = 0
                                IF Error_Happened THEN GOTO errmes
                            END IF

                            dimsfarray = 0
                            r$ = refer$(_TOSTR$(currentid), id.t, 1)
                            IF Error_Happened THEN GOTO errmes
                            WriteBufRawData RegTxtBuf, "ptrszint*" + r$
                            WriteBufRawData MainTxtBuf, "ptrszint*" + r$
                        ELSE

                            IF declaringlibrary THEN
                                'is it a udt?
                                FOR xx = 1 TO lasttype
                                    IF t2$ = RTRIM$(udtxname(xx)) THEN
                                        WriteBufLine RegTxtBuf, "void*"
                                        GOTO decudt
                                    END IF
                                NEXT
                                t$ = typ2ctyp$(0, t2$)

                                IF Error_Happened THEN GOTO errmes
                                IF t$ = "qbs" THEN
                                    t$ = "char*"
                                    IF byvalue = 1 THEN a$ = "STRINGs cannot be passed using BYVAL": GOTO errmes
                                    byvalue = 1 'use t$ as is
                                END IF
                                IF byvalue THEN WriteBufRawData RegTxtBuf, t$ ELSE WriteBufRawData RegTxtBuf, t$ + "*"
                                decudt:
                                GOTO declibjmp3
                            END IF

                            argdynmode = ASC(MID$(id2.dynudtargmode, params, 1))
                            IF argdynmode < 0 OR argdynmode > 1 THEN argdynmode = 0
                            dimsfarray = 1
                            sf_udt_dynmode = argdynmode
                            ignore = dim2(n2$, t2$, dimmethod, "")
                            sf_udt_dynmode = 0
                            IF Error_Happened THEN GOTO errmes


                            dimsfarray = 0
                            t$ = ""
                            typ = id.t 'the typ of the ID created by dim2

                            t$ = typ2ctyp$(typ, "")
                            IF Error_Happened THEN GOTO errmes



                            IF t$ = "" THEN a$ = "Cannot find C type to return array data": GOTO errmes
                            'searchpoint
                            'get the name of the variable
                            r$ = refer$(_TOSTR$(currentid), id.t, 1)
                            IF Error_Happened THEN GOTO errmes
                            WriteBufRawData RegTxtBuf, t$ + "*" + r$
                            WriteBufRawData MainTxtBuf, t$ + "*" + r$
                            IF t$ = "qbs" THEN
                                u$ = _TOSTR$(uniquenumber)
                                WriteBufLine DataTxtBuf, "qbs*oldstr" + u$ + "=NULL;"
                                WriteBufLine DataTxtBuf, "if(" + r$ + "->tmp||" + r$ + "->fixed||" + r$ + "->readonly){"
                                WriteBufLine DataTxtBuf, "oldstr" + u$ + "=" + r$ + ";"

                                WriteBufLine DataTxtBuf, "if (oldstr" + u$ + "->cmem_descriptor){"
                                WriteBufLine DataTxtBuf, r$ + "=qbs_new_cmem(oldstr" + u$ + "->len,0);"
                                WriteBufLine DataTxtBuf, "}else{"
                                WriteBufLine DataTxtBuf, r$ + "=qbs_new(oldstr" + u$ + "->len,0);"
                                WriteBufLine DataTxtBuf, "}"

                                WriteBufLine DataTxtBuf, "memcpy(" + r$ + "->chr,oldstr" + u$ + "->chr,oldstr" + u$ + "->len);"
                                WriteBufLine DataTxtBuf, "}"

                                WriteBufLine FreeTxtBuf, "if(oldstr" + u$ + "){"
                                WriteBufLine FreeTxtBuf, "if(oldstr" + u$ + "->fixed)qbs_set(oldstr" + u$ + "," + r$ + ");"
                                WriteBufLine FreeTxtBuf, "qbs_free(" + r$ + ");"
                                WriteBufLine FreeTxtBuf, "}"
                            END IF
                        END IF
                        declibjmp3:
                        IF i <> n - 1 THEN l$ = l$ + sp2 + ","

                        a2$ = ""
                    ELSE
                        a2$ = a2$ + e$ + sp
                        IF i = n - 1 THEN GOTO getlastparam2
                    END IF
                NEXT i
                nosfparams2:
                l$ = l$ + sp2 + ")"
            END IF 'n>2
            AllowLocalName = 0

            IF addstatic2layout THEN l$ = l$ + sp + SCase$("Static")
            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$

            WriteBufLine RegTxtBuf, ");"

            IF declaringlibrary THEN GOTO declibjmp4

            WriteBufLine MainTxtBuf, "){"
            WriteBufLine MainTxtBuf, "qbs *tqbs;"
            WriteBufLine MainTxtBuf, "ptrszint tmp_long;"
            WriteBufLine MainTxtBuf, "int32 tmp_fileno;"
            WriteBufLine MainTxtBuf, "uint32 qbs_tmp_base=qbs_tmp_list_nexti;"
            WriteBufLine MainTxtBuf, "uint8 *tmp_mem_static_pointer=mem_static_pointer;"
            WriteBufLine MainTxtBuf, "uint32 tmp_cmem_sp=cmem_sp;"
            WriteBufLine MainTxtBuf, "#include " + CHR$(34) + "data" + _TOSTR$(subfuncn) + ".txt" + CHR$(34)

            'create new _MEM lock for this scope
            WriteBufLine MainTxtBuf, "mem_lock *sf_mem_lock;" 'MUST not be static for recursion reasons
            WriteBufLine MainTxtBuf, "new_mem_lock();"
            WriteBufLine MainTxtBuf, "sf_mem_lock=mem_lock_tmp;"
            WriteBufLine MainTxtBuf, "sf_mem_lock->type=3;"

            ' Native recursion can exhaust the C++ thread stack before error(256)
            ' is reached. Check every user SUB/FUNCTION entry while enough stack
            ' remains to report the error. $ErrorLocation controls only whether
            ' the report includes a BASIC source position; stack exhaustion must
            ' still be caught when source tracking is disabled. The runtime helper
            ' uses platform-specific stack bounds behind one common interface.
            WriteBufLine MainTxtBuf, "libqb_check_stack();"

            IF GetRCStateVar(vWatchOn) THEN
                WriteBufLine MainTxtBuf, "*__LONG_VWATCH_SUBLEVEL=*__LONG_VWATCH_SUBLEVEL+ 1 ;"
                IF subfunc <> "SUB_VWATCH" THEN
                    inclinenump$ = ""
                    IF inclinenumber(inclevel) THEN
                        thisincname$ = getfilepath$(incname$(inclevel))
                        thisincname$ = MID$(incname$(inclevel), LEN(thisincname$) + 1)
                        inclinenump$ = "(" + thisincname$ + "," + STR$(inclinenumber(inclevel)) + ") "
                    END IF

                    WriteBufLine MainTxtBuf, "qbs_set(__STRING_VWATCH_SUBNAME,qbs_new_txt_len(" + CHR$(34) + inclinenump$ + subfuncoriginalname$ + CHR$(34) + "," + _TOSTR$(LEN(inclinenump$ + subfuncoriginalname$)) + "));"
                    WriteBufLine MainTxtBuf, "qbs_cleanup(qbs_tmp_base,0);"
                    WriteBufLine MainTxtBuf, "qbs_set(__STRING_VWATCH_INTERNALSUBNAME,qbs_new_txt_len(" + CHR$(34) + subfunc + CHR$(34) + "," + _TOSTR$(LEN(subfunc)) + "));"
                    WriteBufLine MainTxtBuf, "qbs_cleanup(qbs_tmp_base,0);"
                    WriteBufLine MainTxtBuf, "*__LONG_VWATCH_LINENUMBER=-2; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars);"
                END IF
            END IF

            WriteBufLine MainTxtBuf, "if (is_error_pending()) goto exit_subfunc;"

            'statementn = statementn + 1
            'if nochecks=0 then WriteBufLine MainTxtBuf, "S_" + _TOSTR$(statementn) + ":;"

            dimstatic = staticsf

            declibjmp4:

            IF declaringlibrary THEN

                IF customtypelibrary THEN

                    callname$ = removecast$(RTRIM$(id2.callname))

                    WriteBufLine RegTxtBuf, "CUSTOMCALL_" + callname$ + " *" + callname$ + "=NULL;"

                    IF subfuncn THEN
                        f = OpenBuffer%("A", tmpdir$ + "maindata.txt")
                    ELSE
                        f = DataTxtBuf
                    END IF

                    WriteBufLine f, callname$ + "=(CUSTOMCALL_" + callname$ + "*)&" + aliasname$ + ";"

                    'if no header exists to make the external function available, the function definition must be found
                    IF sfheader = 0 AND sfdeclare <> 0 THEN
                        ResolveStaticFunctions = ResolveStaticFunctions + 1
                        'expand array if necessary
                        IF ResolveStaticFunctions > UBOUND(ResolveStaticFunction_Name) THEN
                            REDIM _PRESERVE ResolveStaticFunction_Name(1 TO ResolveStaticFunctions + 100) AS STRING
                            REDIM _PRESERVE ResolveStaticFunction_File(1 TO ResolveStaticFunctions + 100) AS STRING
                            REDIM _PRESERVE ResolveStaticFunction_Method(1 TO ResolveStaticFunctions + 100) AS LONG
                        END IF
                        ResolveStaticFunction_File(ResolveStaticFunctions) = libname$
                        ResolveStaticFunction_Name(ResolveStaticFunctions) = aliasname$
                        ResolveStaticFunction_Method(ResolveStaticFunctions) = 1
                    END IF 'sfheader=0

                END IF

                IF dynamiclibrary THEN
                    IF sfdeclare THEN

                        WriteBufLine RegTxtBuf, "DLLCALL_" + removecast$(RTRIM$(id2.callname)) + " " + removecast$(RTRIM$(id2.callname)) + "=NULL;"

                        IF subfuncn THEN
                            f = OpenBuffer%("A", tmpdir$ + "maindata.txt")
                        ELSE
                            f = DataTxtBuf
                        END IF

                        'Dynamic symbol resolution also runs outside the normal statement path.
                        'Capture the individual SUB/FUNCTION declaration line only if lookup fails.
                        errortrackcall$ = ""
                        IF GetRCStateVar(ErrorLocationMode) = 2 THEN
                            IF inclinenumber(inclevel) THEN
                                thisincname$ = getfilepath$(incname$(inclevel))
                                thisincname$ = MID$(incname$(inclevel), LEN(thisincname$) + 1)
                                errortrackcall$ = "error_track_line(" + _TOSTR$(linenumber) + "," + _TOSTR$(inclinenumber(inclevel)) + "," + CHR$(34) + thisincname$ + CHR$(34) + ");"
                            ELSE
                                errortrackcall$ = "error_track_line(" + _TOSTR$(linenumber) + ",0,NULL);"
                            END IF
                        END IF

                        WriteBufLine f, "if (!" + removecast$(RTRIM$(id2.callname)) + "){"
                        IF os$ = "WIN" THEN
                            WriteBufLine f, removecast$(RTRIM$(id2.callname)) + "=(DLLCALL_" + removecast$(RTRIM$(id2.callname)) + ")GetProcAddress(DLL_" + DLLname$ + "," + CHR$(34) + aliasname$ + CHR$(34) + ");"
                            WriteBufLine f, "if (!" + removecast$(RTRIM$(id2.callname)) + "){" + errortrackcall$ + "error(260);}"
                        END IF
                        IF os$ = "LNX" THEN
                            WriteBufLine f, removecast$(RTRIM$(id2.callname)) + "=(DLLCALL_" + removecast$(RTRIM$(id2.callname)) + ")dlsym(DLL_" + DLLname$ + "," + CHR$(34) + aliasname$ + CHR$(34) + ");"
                            WriteBufLine f, "if (dlerror()){" + errortrackcall$ + "error(260);}"
                        END IF
                        WriteBufLine f, "}"

                    END IF 'sfdeclare
                END IF 'dynamic

                IF sfdeclare = 1 AND customtypelibrary = 0 AND dynamiclibrary = 0 AND indirectlibrary = 0 THEN
                    ResolveStaticFunctions = ResolveStaticFunctions + 1
                    'expand array if necessary
                    IF ResolveStaticFunctions > UBOUND(ResolveStaticFunction_Name) THEN
                        REDIM _PRESERVE ResolveStaticFunction_Name(1 TO ResolveStaticFunctions + 100) AS STRING
                        REDIM _PRESERVE ResolveStaticFunction_File(1 TO ResolveStaticFunctions + 100) AS STRING
                        REDIM _PRESERVE ResolveStaticFunction_Method(1 TO ResolveStaticFunctions + 100) AS LONG
                    END IF
                    ResolveStaticFunction_File(ResolveStaticFunctions) = libname$
                    ResolveStaticFunction_Name(ResolveStaticFunctions) = aliasname$
                    ResolveStaticFunction_Method(ResolveStaticFunctions) = 2
                END IF

                IF sfdeclare = 0 AND indirectlibrary = 0 THEN
                    RegTxtBuf = OpenBuffer%("A", tmpdir$ + "regsf.txt")
                END IF

            END IF 'declaring library

            GOTO finishednonexec
        END IF
    END IF

    'END SUB/FUNCTION
    IF n = 2 THEN
        IF firstelement$ = "END" THEN
            sf = 0
            IF secondelement$ = "FUNCTION" THEN sf = 1
            IF secondelement$ = "SUB" THEN sf = 2
            IF sf THEN

                IF LEN(subfunc) = 0 THEN a$ = "END " + secondelement$ + " without " + secondelement$: GOTO errmes

                'check for open controls (copy #3)
                IF controllevel <> 0 AND controltype(controllevel) <> 6 AND controltype(controllevel) <> 32 THEN 'It's OK for subs to be inside $IF blocks
                    a$ = "Unidentified open control block"
                    SELECT CASE controltype(controllevel)
                        CASE 1: a$ = "IF without END IF"
                        CASE 2: a$ = "FOR without NEXT"
                        CASE 3, 4: a$ = "DO without LOOP"
                        CASE 5: a$ = "WHILE without WEND"
                        CASE 10 TO 19: a$ = "SELECT CASE without END SELECT"
                    END SELECT
                    linenumber = controlref(controllevel)
                    GOTO errmes
                END IF

                IF controltype(controllevel) = 32 AND IDEIndentSubs THEN
                    controltype(controllevel) = 0
                    controllevel = controllevel - 1
                END IF

                IF LEFT$(subfunc, 4) = "SUB_" THEN secondelement$ = SCase$("Sub") ELSE secondelement$ = SCase$("Function")
                l$ = SCase$("End") + sp + secondelement$
                layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$

                IF GetRCStateVar(vWatchOn) THEN
                    vWatchVariable "", 1
                END IF

                staticarraylist = "": staticarraylistn = 0 'remove previously listed arrays
                dimstatic = 0
                WriteBufLine MainTxtBuf, "exit_subfunc:;"
                IF GetRCStateVar(vWatchOn) THEN
                    IF CheckingOn = 1 AND inclinenumber(inclevel) = 0 THEN
                        vWatchAddLabel linenumber, 0
                        WriteBufLine MainTxtBuf, "*__LONG_VWATCH_LINENUMBER= " + _TOSTR$(linenumber) + "; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars); if (*__LONG_VWATCH_GOTO>0) goto VWATCH_SETNEXTLINE; if (*__LONG_VWATCH_GOTO<0) goto VWATCH_SKIPLINE;"
                        vWatchAddLabel 0, -1
                    END IF
                    WriteBufLine MainTxtBuf, "*__LONG_VWATCH_SUBLEVEL=*__LONG_VWATCH_SUBLEVEL- 1 ;"

                    IF inclinenumber(inclevel) = 0 AND firstLineNumberLabelvWatch > 0 THEN
                        WriteBufLine MainTxtBuf, "goto VWATCH_SKIPSETNEXTLINE;"
                        WriteBufLine MainTxtBuf, "VWATCH_SETNEXTLINE:;"
                        WriteBufLine MainTxtBuf, "switch (*__LONG_VWATCH_GOTO) {"
                        FOR i = firstLineNumberLabelvWatch TO lastLineNumberLabelvWatch
                            WHILE i > LEN(vWatchUsedLabels)
                                vWatchUsedLabels = vWatchUsedLabels + SPACE$(1000)
                                vWatchUsedSkipLabels = vWatchUsedSkipLabels + SPACE$(1000)
                            WEND
                            IF ASC(vWatchUsedLabels, i) = 1 THEN
                                WriteBufLine MainTxtBuf, "    case " + _TOSTR$(i) + ":"
                                WriteBufLine MainTxtBuf, "        goto VWATCH_LABEL_" + _TOSTR$(i) + ";"
                                WriteBufLine MainTxtBuf, "        break;"
                            END IF
                        NEXT
                        WriteBufLine MainTxtBuf, "    default:"
                        WriteBufLine MainTxtBuf, "        *__LONG_VWATCH_GOTO=*__LONG_VWATCH_LINENUMBER;"
                        WriteBufLine MainTxtBuf, "        goto VWATCH_SETNEXTLINE;"
                        WriteBufLine MainTxtBuf, "}"

                        WriteBufLine MainTxtBuf, "VWATCH_SKIPLINE:;"
                        WriteBufLine MainTxtBuf, "switch (*__LONG_VWATCH_GOTO) {"
                        FOR i = firstLineNumberLabelvWatch TO lastLineNumberLabelvWatch
                            IF ASC(vWatchUsedSkipLabels, i) = 1 THEN
                                WriteBufLine MainTxtBuf, "    case -" + _TOSTR$(i) + ":"
                                WriteBufLine MainTxtBuf, "        goto VWATCH_SKIPLABEL_" + _TOSTR$(i) + ";"
                                WriteBufLine MainTxtBuf, "        break;"
                            END IF
                        NEXT
                        WriteBufLine MainTxtBuf, "}"

                        WriteBufLine MainTxtBuf, "VWATCH_SKIPSETNEXTLINE:;"
                    END IF
                    firstLineNumberLabelvWatch = 0
                END IF

                'release _MEM lock for this scope
                WriteBufLine MainTxtBuf, "free_mem_lock(sf_mem_lock);"

                WriteBufLine MainTxtBuf, "#include " + CHR$(34) + "free" + _TOSTR$(subfuncn) + ".txt" + CHR$(34)
                WriteBufLine MainTxtBuf, "if ((tmp_mem_static_pointer>=mem_static)&&(tmp_mem_static_pointer<=mem_static_limit)) mem_static_pointer=tmp_mem_static_pointer; else mem_static_pointer=mem_static;"
                WriteBufLine MainTxtBuf, "cmem_sp=tmp_cmem_sp;"
                IF subfuncret$ <> "" THEN WriteBufLine MainTxtBuf, subfuncret$

                WriteBufLine MainTxtBuf, "}" 'skeleton sub
                'ret???.txt
                WriteBufLine RetTxtBuf, "}" 'end case
                WriteBufLine RetTxtBuf, "}"
                WriteBufLine RetTxtBuf, "error(3);" 'no valid return possible
                subfunc = ""
                subfuncn = 0
                MainTxtBuf = OpenBuffer%("A", tmpdir$ + "main0.txt")
                DataTxtBuf = OpenBuffer%("A", tmpdir$ + "maindata.txt")
                defdatahandle = GlobTxtBuf
                FreeTxtBuf = OpenBuffer%("A", tmpdir$ + "mainfree.txt")
                RetTxtBuf = OpenBuffer%("A", tmpdir$ + "ret0.txt")

                'unshare temp. shared variables
                FOR i = 1 TO idn
                    IF ids(i).share AND 2 THEN ids(i).share = ids(i).share - 2
                NEXT

                FOR i = 1 TO revertmaymusthaven
                    x = revertmaymusthave(i)
                    SWAP ids(x).musthave, ids(x).mayhave
                NEXT
                revertmaymusthaven = 0
                GOTO finishednonexec

            END IF
        END IF
    END IF



    IF n >= 1 AND firstelement$ = "CONST" THEN
        l$ = SCase$("Const")
        'DEF... do not change type, the expression is stored in a suitable type
        'based on its value if type isn't forced/specified
        IF n < 3 THEN a$ = "Expected CONST name = value/expression": GOTO errmes
        i = 2

        constdefpending:
        pending = 0

        n$ = getelement$(ca$, i): i = i + 1
        l$ = l$ + sp + n$ + sp + "="
        typeoverride = 0
        s$ = removesymbol$(n$)
        IF Error_Happened THEN GOTO errmes
        IF s$ <> "" THEN
            typeoverride = typname2typ(s$)
            IF Error_Happened THEN GOTO errmes
            IF typeoverride AND ISFIXEDLENGTH THEN a$ = "Invalid constant type": GOTO errmes
            IF typeoverride = 0 THEN a$ = "Invalid constant type": GOTO errmes
        END IF

        IF getelement$(a$, i) <> "=" THEN a$ = "Expected =": GOTO errmes
        i = i + 1

        'get expression
        e$ = ""
        B = 0
        FOR i2 = i TO n
            e2$ = getelement$(ca$, i2)
            IF e2$ = "(" THEN B = B + 1
            IF e2$ = ")" THEN B = B - 1
            IF e2$ = "," AND B = 0 THEN
                pending = 1
                i = i2 + 1
                IF i > n - 2 THEN a$ = "Expected CONST ... , name = value/expression": GOTO errmes
                EXIT FOR
            END IF
            IF LEN(e$) = 0 THEN e$ = e2$ ELSE e$ = e$ + sp + e2$
        NEXT

        e$ = fixoperationorder(e$)
        IF Error_Happened THEN GOTO errmes
        l$ = l$ + sp + tlayout$

        'Note: Actual CONST definition handled in prepass

        'Set CONST as defined
        hashname$ = n$
        hashchkflags = HASHFLAG_CONSTANT
        hashres = HashFind(hashname$, hashchkflags, hashresflags, hashresref)
        DO WHILE hashres
            IF constsubfunc(hashresref) = subfuncn THEN constdefined(hashresref) = 1: EXIT DO
            IF hashres <> 1 THEN hashres = HashFindCont(hashresflags, hashresref) ELSE hashres = 0
        LOOP

        IF pending THEN l$ = l$ + sp2 + ",": GOTO constdefpending

        layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$

        GOTO finishednonexec
    END IF

    predefine:
    IF n >= 2 THEN
        asreq = 0
        IF firstelement$ = "DEFINT" THEN l$ = SCase$("DefInt"): a$ = a$ + sp + "AS" + sp + "INTEGER": n = n + 2: GOTO definetype
        IF firstelement$ = "DEFLNG" THEN l$ = SCase$("DefLng"): a$ = a$ + sp + "AS" + sp + "LONG": n = n + 2: GOTO definetype
        IF firstelement$ = "DEFSNG" THEN l$ = SCase$("DefSng"): a$ = a$ + sp + "AS" + sp + "SINGLE": n = n + 2: GOTO definetype
        IF firstelement$ = "DEFDBL" THEN l$ = SCase$("DefDbl"): a$ = a$ + sp + "AS" + sp + "DOUBLE": n = n + 2: GOTO definetype
        IF firstelement$ = "DEFSTR" THEN l$ = SCase$("DefStr"): a$ = a$ + sp + "AS" + sp + "STRING": n = n + 2: GOTO definetype
        IF firstelement$ = "_DEFINE" THEN
            asreq = 1
            l$ = SCase$("_Define")
            definetype:
            'get type from rhs
            typ$ = ""
            typ2$ = ""
            t$ = ""
            FOR i = n TO 2 STEP -1
                t$ = getelement$(a$, i)
                IF t$ = "AS" THEN EXIT FOR
                typ$ = t$ + " " + typ$
                typ2$ = t$ + sp + typ2$
            NEXT
            typ$ = RTRIM$(typ$)
            IF t$ <> "AS" THEN a$ = "_DEFINE: Expected ... AS ...": GOTO errmes
            IF i = n OR i = 2 THEN a$ = "_DEFINE: Expected ... AS ...": GOTO errmes


            n = i - 1
            'the data is from element 2 to element n
            i = 2 - 1
            definenext:
            'expects an alphabet letter or underscore
            i = i + 1: e$ = getelement$(a$, i): E = ASC(UCASE$(e$))
            IF LEN(e$) > 1 THEN a$ = "_DEFINE: Expected an alphabet letter or the underscore character (_)": GOTO errmes
            IF E <> 95 AND (E > 90 OR E < 65) THEN a$ = "_DEFINE: Expected an alphabet letter or the underscore character (_)": GOTO errmes
            IF E = 95 THEN E = 27 ELSE E = E - 64
            defineaz(E) = typ$
            defineextaz(E) = type2symbol(typ$)
            IF Error_Happened THEN GOTO errmes
            firste = E
            l$ = l$ + sp + e$

            IF i = n THEN
                IF predefining = 1 THEN GOTO predefined
                IF asreq THEN l$ = l$ + sp + SCase$("As") + sp + typ2$
                layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                GOTO finishednonexec
            END IF

            'expects "-" or ","
            i = i + 1: e$ = getelement$(a$, i)
            IF e$ <> "-" AND e$ <> "," THEN a$ = "_DEFINE: Expected - or ,": GOTO errmes
            IF e$ = "-" THEN
                l$ = l$ + sp2 + "-"
                IF i = n THEN a$ = "_DEFINE: Syntax incomplete": GOTO errmes
                'expects an alphabet letter or underscore
                i = i + 1: e$ = getelement$(a$, i): E = ASC(UCASE$(e$))
                IF LEN(e$) > 1 THEN a$ = "_DEFINE: Expected an alphabet letter or the underscore character (_)": GOTO errmes
                IF E <> 95 AND (E > 90 OR E < 65) THEN a$ = "_DEFINE: Expected an alphabet letter or the underscore character (_)": GOTO errmes
                IF E = 95 THEN E = 27 ELSE E = E - 64
                IF firste > E THEN SWAP E, firste
                FOR e2 = firste TO E
                    defineaz(e2) = typ$
                    defineextaz(e2) = type2symbol(typ$)
                    IF Error_Happened THEN GOTO errmes
                NEXT
                l$ = l$ + sp2 + e$
                IF i = n THEN
                    IF predefining = 1 THEN GOTO predefined
                    IF asreq THEN l$ = l$ + sp + SCase$("As") + sp + typ2$
                    layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                    GOTO finishednonexec
                END IF
                'expects ","
                i = i + 1: e$ = getelement$(a$, i)
                IF e$ <> "," THEN a$ = "_DEFINE: Expected ,": GOTO errmes
            END IF
            l$ = l$ + sp2 + ","
            GOTO definenext
        END IF '_DEFINE
    END IF '2
    IF predefining = 1 THEN GOTO predefined

    'executable section:

    statementn = statementn + 1

    'Track the current BASIC source line before executing generated code.
    'Fatal runtime errors such as division by zero may occur before the
    'normal post-statement evnt() path is reached, so keep this separately.
    '$ErrorLocation is a whole-program opt-in diagnostic mode; it is OFF by default.
    IF GetRCStateVar(ErrorLocationMode) = 2 THEN
        IF inclinenumber(inclevel) THEN
            thisincname$ = getfilepath$(incname$(inclevel))
            thisincname$ = MID$(incname$(inclevel), LEN(thisincname$) + 1)
            WriteBufLine MainTxtBuf, "error_track_line(" + _TOSTR$(linenumber) + "," + _TOSTR$(inclinenumber(inclevel)) + "," + CHR$(34) + thisincname$ + CHR$(34) + ");"
        ELSE
            WriteBufLine MainTxtBuf, "error_track_line(" + _TOSTR$(linenumber) + ",0,NULL);"
        END IF
    END IF

    IF n >= 1 THEN
        IF firstelement$ = "NEXT" THEN

            l$ = SCase$("Next")
            IF n = 1 THEN GOTO simplenext
            v$ = ""
            FOR i = 2 TO n
                a2$ = getelement(ca$, i)

                IF a2$ = "," THEN

                    lastnextele:
                    e$ = fixoperationorder(v$)
                    IF Error_Happened THEN GOTO errmes
                    IF LEN(l$) = 4 THEN l$ = l$ + sp + tlayout$ ELSE l$ = l$ + sp2 + "," + sp + tlayout$
                    e$ = evaluate(e$, typ)
                    IF Error_Happened THEN GOTO errmes
                    IF (typ AND ISREFERENCE) THEN
                        getid VAL(e$)
                        IF Error_Happened THEN GOTO errmes
                        IF (id.t AND ISPOINTER) THEN
                            IF (id.t AND ISSTRING) = 0 THEN
                                IF (id.t AND ISOFFSETINBITS) = 0 THEN
                                    IF (id.t AND ISARRAY) = 0 THEN
                                        GOTO fornextfoundvar2
                                    END IF
                                END IF
                            END IF
                        END IF
                    END IF
                    a$ = "Unsupported variable after NEXT": GOTO errmes
                    fornextfoundvar2:
                    simplenext:
                    IF controltype(controllevel) <> 2 THEN a$ = "NEXT without FOR": GOTO errmes
                    IF n <> 1 AND controlvalue(controllevel) <> currentid THEN a$ = "Incorrect variable after NEXT": GOTO errmes
                    WriteBufLine MainTxtBuf, "fornext_continue_" + _TOSTR$(controlid(controllevel)) + ":;"
                    IF GetRCStateVar(vWatchOn) = 1 AND inclinenumber(inclevel) = 0 AND CheckingOn = 1 THEN
                        vWatchAddLabel linenumber, 0
                        WriteBufLine MainTxtBuf, "*__LONG_VWATCH_LINENUMBER= " + _TOSTR$(linenumber) + "; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars); if (*__LONG_VWATCH_GOTO>0) goto VWATCH_SETNEXTLINE; if (*__LONG_VWATCH_GOTO<0) goto VWATCH_SKIPLINE;"
                    END IF
                    WriteBufLine MainTxtBuf, "}"
                    WriteBufLine MainTxtBuf, "fornext_exit_" + _TOSTR$(controlid(controllevel)) + ":;"
                    controllevel = controllevel - 1
                    IF n = 1 THEN EXIT FOR
                    v$ = ""

                ELSE

                    IF LEN(v$) THEN v$ = v$ + sp + a2$ ELSE v$ = a2$
                    IF i = n THEN GOTO lastnextele

                END IF

            NEXT

            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
            GOTO finishednonexec '***no error causing code, event checking done by FOR***
        END IF
    END IF



    IF n >= 1 THEN
        IF firstelement$ = "WHILE" THEN
            IF CheckingOn THEN WriteBufLine MainTxtBuf, "S_" + _TOSTR$(statementn) + ":;": dynscope = 1

            'prevents code from being placed before 'CASE condition' in a SELECT CASE block
            IF SelectCaseCounter > 0 AND SelectCaseHasCaseBlock(SelectCaseCounter) = 0 THEN
                a$ = "Expected CASE expression": GOTO errmes
            END IF

            controllevel = controllevel + 1
            controlref(controllevel) = linenumber
            controltype(controllevel) = 5
            controlid(controllevel) = uniquenumber
            IF n >= 2 THEN
                e$ = fixoperationorder(getelements$(ca$, 2, n))
                IF Error_Happened THEN GOTO errmes
                l$ = SCase$("While") + sp + tlayout$
                layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                e$ = evaluate(e$, typ)
                IF Error_Happened THEN GOTO errmes
                IF (typ AND ISREFERENCE) THEN e$ = refer$(e$, typ, 0)
                IF Error_Happened THEN GOTO errmes
                IF stringprocessinghappened THEN e$ = cleanupstringprocessingcall$ + e$ + ")"
                IF (typ AND ISSTRING) THEN a$ = "WHILE ERROR! Cannot accept a STRING type.": GOTO errmes
                IF CheckingOn = 1 AND GetRCStateVar(vWatchOn) = 1 AND inclinenumber(inclevel) = 0 THEN
                    vWatchAddLabel linenumber, 0
                    WriteBufLine MainTxtBuf, "*__LONG_VWATCH_LINENUMBER= " + _TOSTR$(linenumber) + "; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars); if (*__LONG_VWATCH_GOTO>0) goto VWATCH_SETNEXTLINE; if (*__LONG_VWATCH_GOTO<0) goto VWATCH_SKIPLINE;"
                END IF
                WriteBufLine MainTxtBuf, "while((" + e$ + ")||is_error_pending()){"
            ELSE
                a$ = "WHILE ERROR! Expected expression after WHILE.": GOTO errmes
            END IF

            GOTO finishedline
        END IF
    END IF

    IF n = 1 THEN
        IF firstelement$ = "WEND" THEN


            IF controltype(controllevel) <> 5 THEN a$ = "WEND without WHILE": GOTO errmes
            WriteBufLine MainTxtBuf, "ww_continue_" + _TOSTR$(controlid(controllevel)) + ":;"
            WriteBufLine MainTxtBuf, "}"
            WriteBufLine MainTxtBuf, "ww_exit_" + _TOSTR$(controlid(controllevel)) + ":;"
            controllevel = controllevel - 1
            l$ = SCase$("Wend")
            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
            GOTO finishednonexec '***no error causing code, event checking done by WHILE***
        END IF
    END IF





    IF n >= 1 THEN
        IF firstelement$ = "DO" THEN
            IF CheckingOn THEN WriteBufLine MainTxtBuf, "S_" + _TOSTR$(statementn) + ":;": dynscope = 1

            'prevents code from being placed before 'CASE condition' in a SELECT CASE block
            IF SelectCaseCounter > 0 AND SelectCaseHasCaseBlock(SelectCaseCounter) = 0 THEN
                a$ = "Expected CASE expression": GOTO errmes
            END IF

            controllevel = controllevel + 1
            controlref(controllevel) = linenumber
            l$ = SCase$("Do")
            IF n >= 2 THEN
                whileuntil = 0
                IF secondelement$ = "WHILE" THEN whileuntil = 1: l$ = l$ + sp + SCase$("While")
                IF secondelement$ = "UNTIL" THEN whileuntil = 2: l$ = l$ + sp + SCase$("Until")
                IF whileuntil = 0 THEN a$ = "DO ERROR! Expected WHILE or UNTIL after DO.": GOTO errmes
                IF whileuntil > 0 AND n = 2 THEN a$ = "Condition expected after WHILE/UNTIL": GOTO errmes
                e$ = fixoperationorder(getelements$(ca$, 3, n))
                IF Error_Happened THEN GOTO errmes
                l$ = l$ + sp + tlayout$
                e$ = evaluate(e$, typ)
                IF Error_Happened THEN GOTO errmes
                IF (typ AND ISREFERENCE) THEN e$ = refer$(e$, typ, 0)
                IF Error_Happened THEN GOTO errmes
                IF stringprocessinghappened THEN e$ = cleanupstringprocessingcall$ + e$ + ")"
                IF (typ AND ISSTRING) THEN a$ = "DO ERROR! Cannot accept a STRING type.": GOTO errmes
                IF whileuntil = 1 THEN WriteBufLine MainTxtBuf, "while((" + e$ + ")||is_error_pending()){" ELSE WriteBufLine MainTxtBuf, "while((!(" + e$ + "))||is_error_pending()){"
                IF CheckingOn = 1 AND GetRCStateVar(vWatchOn) = 1 AND inclinenumber(inclevel) = 0 THEN
                    vWatchAddLabel linenumber, 0
                    WriteBufLine MainTxtBuf, "*__LONG_VWATCH_LINENUMBER= " + _TOSTR$(linenumber) + "; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars); if (*__LONG_VWATCH_GOTO>0) goto VWATCH_SETNEXTLINE; if (*__LONG_VWATCH_GOTO<0) goto VWATCH_SKIPLINE;"
                END IF
                controltype(controllevel) = 4
            ELSE
                controltype(controllevel) = 3
                IF GetRCStateVar(vWatchOn) = 1 AND inclinenumber(inclevel) = 0 AND CheckingOn = 1 THEN
                    vWatchAddLabel linenumber, 0
                    WriteBufLine MainTxtBuf, "do{*__LONG_VWATCH_LINENUMBER= " + _TOSTR$(linenumber) + "; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars); if (*__LONG_VWATCH_GOTO>0) goto VWATCH_SETNEXTLINE; if (*__LONG_VWATCH_GOTO<0) goto VWATCH_SKIPLINE;"
                ELSE
                    WriteBufLine MainTxtBuf, "do{"
                END IF
            END IF
            controlid(controllevel) = uniquenumber
            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
            GOTO finishedline
        END IF
    END IF

    IF n >= 1 THEN
        IF firstelement$ = "LOOP" THEN
            l$ = SCase$("Loop")
            IF controltype(controllevel) <> 3 AND controltype(controllevel) <> 4 THEN a$ = "PROGRAM FLOW ERROR!": GOTO errmes
            IF n >= 2 THEN
                IF CheckingOn THEN WriteBufLine MainTxtBuf, "S_" + _TOSTR$(statementn) + ":;": dynscope = 1
                IF controltype(controllevel) = 4 THEN a$ = "PROGRAM FLOW ERROR!": GOTO errmes
                whileuntil = 0
                IF secondelement$ = "WHILE" THEN whileuntil = 1: l$ = l$ + sp + SCase$("While")
                IF secondelement$ = "UNTIL" THEN whileuntil = 2: l$ = l$ + sp + SCase$("Until")
                IF whileuntil = 0 THEN a$ = "LOOP ERROR! Expected WHILE or UNTIL after LOOP.": GOTO errmes
                IF whileuntil > 0 AND n = 2 THEN a$ = "Condition expected after WHILE/UNTIL": GOTO errmes
                e$ = fixoperationorder(getelements$(ca$, 3, n))
                IF Error_Happened THEN GOTO errmes
                l$ = l$ + sp + tlayout$
                e$ = evaluate(e$, typ)
                IF Error_Happened THEN GOTO errmes
                IF (typ AND ISREFERENCE) THEN e$ = refer$(e$, typ, 0)
                IF Error_Happened THEN GOTO errmes
                IF stringprocessinghappened THEN e$ = cleanupstringprocessingcall$ + e$ + ")"
                IF (typ AND ISSTRING) THEN a$ = "LOOP ERROR! Cannot accept a STRING type.": GOTO errmes
                WriteBufLine MainTxtBuf, "dl_continue_" + _TOSTR$(controlid(controllevel)) + ":;"
                IF CheckingOn = 1 AND GetRCStateVar(vWatchOn) = 1 AND inclinenumber(inclevel) = 0 THEN
                    vWatchAddLabel linenumber, 0
                    WriteBufLine MainTxtBuf, "*__LONG_VWATCH_LINENUMBER= " + _TOSTR$(linenumber) + "; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars); if (*__LONG_VWATCH_GOTO>0) goto VWATCH_SETNEXTLINE; if (*__LONG_VWATCH_GOTO<0) goto VWATCH_SKIPLINE;"
                END IF
                IF whileuntil = 1 THEN WriteBufLine MainTxtBuf, "}while((" + e$ + ")&&(!is_error_pending()));" ELSE WriteBufLine MainTxtBuf, "}while((!(" + e$ + "))&&(!is_error_pending()));"
            ELSE
                WriteBufLine MainTxtBuf, "dl_continue_" + _TOSTR$(controlid(controllevel)) + ":;"

                IF CheckingOn = 1 AND GetRCStateVar(vWatchOn) = 1 AND inclinenumber(inclevel) = 0 THEN
                    vWatchAddLabel linenumber, 0
                    WriteBufLine MainTxtBuf, "*__LONG_VWATCH_LINENUMBER= " + _TOSTR$(linenumber) + "; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars); if (*__LONG_VWATCH_GOTO>0) goto VWATCH_SETNEXTLINE; if (*__LONG_VWATCH_GOTO<0) goto VWATCH_SKIPLINE;"
                END IF

                IF controltype(controllevel) = 4 THEN
                    WriteBufLine MainTxtBuf, "}"
                ELSE
                    WriteBufLine MainTxtBuf, "}while(1);" 'infinite loop!
                END IF
            END IF
            WriteBufLine MainTxtBuf, "dl_exit_" + _TOSTR$(controlid(controllevel)) + ":;"
            controllevel = controllevel - 1
            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
            IF n = 1 THEN GOTO finishednonexec '***no error causing code, event checking done by DO***
            GOTO finishedline
        END IF
    END IF









    IF n >= 1 THEN
        IF firstelement$ = "FOR" THEN
            IF CheckingOn THEN WriteBufLine MainTxtBuf, "S_" + _TOSTR$(statementn) + ":;": dynscope = 1

            l$ = SCase$("For")

            'prevents code from being placed before 'CASE condition' in a SELECT CASE block
            IF SelectCaseCounter > 0 AND SelectCaseHasCaseBlock(SelectCaseCounter) = 0 THEN
                a$ = "Expected CASE expression": GOTO errmes
            END IF

            controllevel = controllevel + 1
            controlref(controllevel) = linenumber
            controltype(controllevel) = 2
            controlid(controllevel) = uniquenumber

            v$ = ""
            startvalue$ = ""
            p3$ = "1": stepused = 0
            p2$ = ""
            mode = 0
            E = 0
            FOR i = 2 TO n
                e$ = getelement$(a$, i)
                IF e$ = "=" THEN
                    IF mode <> 0 THEN E = 1: EXIT FOR
                    mode = 1
                    v$ = getelements$(ca$, 2, i - 1)
                    equpos = i
                END IF
                IF e$ = "TO" THEN
                    IF mode <> 1 THEN E = 1: EXIT FOR
                    mode = 2
                    startvalue$ = getelements$(ca$, equpos + 1, i - 1)
                    topos = i
                END IF
                IF e$ = "STEP" THEN
                    IF mode <> 2 THEN E = 1: EXIT FOR
                    mode = 3
                    stepused = 1
                    p2$ = getelements$(ca$, topos + 1, i - 1)
                    p3$ = getelements$(ca$, i + 1, n)
                    EXIT FOR
                END IF
            NEXT
            IF mode < 2 THEN E = 1
            IF p2$ = "" THEN p2$ = getelements$(ca$, topos + 1, n)
            IF LEN(v$) = 0 OR LEN(startvalue$) = 0 OR LEN(p2$) = 0 THEN E = 1
            IF E <> 0 AND mode < 3 THEN a$ = "Expected FOR name = start TO end": GOTO errmes
            IF E THEN a$ = "Expected FOR name = start TO end STEP increment": GOTO errmes

            e$ = fixoperationorder(v$)
            IF Error_Happened THEN GOTO errmes
            l$ = l$ + sp + tlayout$
            e$ = evaluate(e$, typ)
            IF Error_Happened THEN GOTO errmes
            IF (typ AND ISREFERENCE) THEN
                getid VAL(e$)
                IF Error_Happened THEN GOTO errmes
                IF (id.t AND ISPOINTER) THEN
                    IF (id.t AND ISSTRING) = 0 THEN
                        IF (id.t AND ISOFFSETINBITS) = 0 THEN
                            IF (id.t AND ISARRAY) = 0 THEN
                                GOTO fornextfoundvar
                            END IF
                        END IF
                    END IF
                END IF
            END IF
            a$ = "Unsupported variable used in FOR statement": GOTO errmes
            fornextfoundvar:
            controlvalue(controllevel) = currentid
            v$ = e$

            'find C++ datatype to match variable
            'markup to cater for greater range/accuracy
            ctype$ = ""
            ctyp = typ - ISPOINTER
            bits = typ AND UDTMASK
            IF (typ AND ISFLOAT) THEN
                IF bits = 32 THEN ctype$ = "double": ctyp = 64& + ISFLOAT
                IF bits = 64 THEN ctype$ = "long double": ctyp = 256& + ISFLOAT
                IF bits = 256 THEN ctype$ = "long double": ctyp = 256& + ISFLOAT
            ELSE
                IF bits = 8 THEN ctype$ = "int16": ctyp = 16&
                IF bits = 16 THEN ctype$ = "int32": ctyp = 32&
                IF bits = 32 THEN ctype$ = "int64": ctyp = 64&
                IF bits = 64 THEN ctype$ = "int64": ctyp = 64&
            END IF
            IF ctype$ = "" THEN a$ = "Unsupported variable used in FOR statement": GOTO errmes
            u$ = _TOSTR$(uniquenumber)

            IF subfunc = "" THEN
                WriteBufLine DataTxtBuf, "static " + ctype$ + " fornext_value" + u$ + ";"
                WriteBufLine DataTxtBuf, "static " + ctype$ + " fornext_finalvalue" + u$ + ";"
                WriteBufLine DataTxtBuf, "static " + ctype$ + " fornext_step" + u$ + ";"
                WriteBufLine DataTxtBuf, "static uint8 fornext_step_negative" + u$ + ";"
            ELSE
                WriteBufLine DataTxtBuf, ctype$ + " fornext_value" + u$ + ";"
                WriteBufLine DataTxtBuf, ctype$ + " fornext_finalvalue" + u$ + ";"
                WriteBufLine DataTxtBuf, ctype$ + " fornext_step" + u$ + ";"
                WriteBufLine DataTxtBuf, "uint8 fornext_step_negative" + u$ + ";"
            END IF

            'calculate start
            e$ = fixoperationorder$(startvalue$)
            IF Error_Happened THEN GOTO errmes
            l$ = l$ + sp + "=" + sp + tlayout$
            e$ = evaluatetotyp$(e$, ctyp)
            IF Error_Happened THEN GOTO errmes
            WriteBufLine MainTxtBuf, "fornext_value" + u$ + "=" + e$ + ";"

            'final
            e$ = fixoperationorder$(p2$)
            IF Error_Happened THEN GOTO errmes
            l$ = l$ + sp + SCase$("To") + sp + tlayout$
            e$ = evaluatetotyp(e$, ctyp)
            IF Error_Happened THEN GOTO errmes
            WriteBufLine MainTxtBuf, "fornext_finalvalue" + u$ + "=" + e$ + ";"

            'step
            e$ = fixoperationorder$(p3$)
            IF Error_Happened THEN GOTO errmes
            IF stepused = 1 THEN l$ = l$ + sp + SCase$("Step") + sp + tlayout$
            e$ = evaluatetotyp(e$, ctyp)
            IF Error_Happened THEN GOTO errmes

            IF CheckingOn = 1 AND GetRCStateVar(vWatchOn) = 1 AND inclinenumber(inclevel) = 0 THEN
                vWatchAddLabel linenumber, 0
                WriteBufLine MainTxtBuf, "*__LONG_VWATCH_LINENUMBER= " + _TOSTR$(linenumber) + "; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars); if (*__LONG_VWATCH_GOTO>0) goto VWATCH_SETNEXTLINE; if (*__LONG_VWATCH_GOTO<0) goto VWATCH_SKIPLINE;"
            END IF

            WriteBufLine MainTxtBuf, "fornext_step" + u$ + "=" + e$ + ";"
            WriteBufLine MainTxtBuf, "if (fornext_step" + u$ + "<0) fornext_step_negative" + u$ + "=1; else fornext_step_negative" + u$ + "=0;"

            WriteBufLine MainTxtBuf, "if (is_error_pending()) goto fornext_error" + u$ + ";"
            WriteBufLine MainTxtBuf, "goto fornext_entrylabel" + u$ + ";"
            WriteBufLine MainTxtBuf, "while(1){"
            typbak = typ
            WriteBufLine MainTxtBuf, "fornext_value" + u$ + "=fornext_step" + u$ + "+(" + refer$(v$, typ, 0) + ");"
            IF Error_Happened THEN GOTO errmes
            typ = typbak
            WriteBufLine MainTxtBuf, "fornext_entrylabel" + u$ + ":"
            setrefer v$, typ, "fornext_value" + u$, 1
            IF Error_Happened THEN GOTO errmes
            WriteBufLine MainTxtBuf, "if (fornext_step_negative" + u$ + "){"
            WriteBufLine MainTxtBuf, "if (fornext_value" + u$ + "<fornext_finalvalue" + u$ + ") break;"
            WriteBufLine MainTxtBuf, "}else{"
            WriteBufLine MainTxtBuf, "if (fornext_value" + u$ + ">fornext_finalvalue" + u$ + ") break;"
            WriteBufLine MainTxtBuf, "}"
            WriteBufLine MainTxtBuf, "fornext_error" + u$ + ":;"

            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$

            GOTO finishedline
        END IF
    END IF


    IF n = 1 THEN
        IF firstelement$ = "ELSE" THEN

            'Routine to add error checking for ELSE so we'll no longer be able to do things like the following:
            'IF x = 1 THEN
            '    SELECT CASE s
            '        CASE 1
            '    END SELECT ELSE y = 2
            'END IF
            'Notice the ELSE with the SELECT CASE?  Before this patch, commands like those were considered valid QB64 code.
            temp$ = UCASE$(LTRIM$(RTRIM$(wholeline)))
            DO WHILE INSTR(temp$, CHR$(9))
                ASC(temp$, INSTR(temp$, CHR$(9))) = 32
            LOOP
            goodelse = 0 'a check to see if it's a good else
            IF LEFT$(temp$, 2) = "IF" THEN goodelse = -1: GOTO skipelsecheck 'If we have an IF, the else is probably good
            IF LEFT$(temp$, 4) = "ELSE" THEN goodelse = -1: GOTO skipelsecheck 'If it's an else by itself,then we'll call it good too at this point and let the rest of the syntax checking check for us
            DO
                spacelocation = INSTR(temp$, " ")
                IF spacelocation THEN temp$ = LEFT$(temp$, spacelocation - 1) + MID$(temp$, spacelocation + 1)
            LOOP UNTIL spacelocation = 0
            IF INSTR(temp$, ":ELSE") OR INSTR(temp$, ":IF") THEN goodelse = -1: GOTO skipelsecheck 'I personally don't like the idea of a :ELSE statement, but this checks for that and validates it as well.  YUCK!  (I suppose this might be useful if there's a label where the ELSE is, like thisline: ELSE
            count = 0
            DO
                count = count + 1
                SELECT CASE MID$(temp$, count, 1)
                    CASE IS = "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", ":"
                    CASE ELSE: EXIT DO
                END SELECT
            LOOP UNTIL count >= LEN(temp$)
            IF MID$(temp$, count, 4) = "ELSE" OR MID$(temp$, count, 2) = "IF" THEN goodelse = -1 'We only had numbers before our else
            IF NOT goodelse THEN a$ = "Invalid Syntax for ELSE": GOTO errmes
            skipelsecheck:
            'End of ELSE Error checking
            FOR i = controllevel TO 1 STEP -1
                t = controltype(i)
                IF t = 1 THEN
                    IF controlstate(controllevel) = 2 THEN a$ = "IF-THEN already contains an ELSE statement": GOTO errmes
                    WriteBufLine MainTxtBuf, "}else{"
                    controlstate(controllevel) = 2
                    IF lineelseused = 0 THEN lhscontrollevel = lhscontrollevel - 1
                    l$ = SCase$("Else")
                    layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                    GOTO finishednonexec '***no error causing code, event checking done by IF***
                END IF
            NEXT
            a$ = "ELSE without IF": GOTO errmes
        END IF
    END IF

    IF n >= 3 THEN
        IF firstelement$ = "ELSEIF" THEN
            IF CheckingOn THEN
                WriteBufLine MainTxtBuf, "S_" + _TOSTR$(statementn) + ":;": dynscope = 1
                IF GetRCStateVar(vWatchOn) = 1 AND inclinenumber(inclevel) = 0 THEN
                    vWatchAddLabel linenumber, 0
                    WriteBufLine MainTxtBuf, "*__LONG_VWATCH_LINENUMBER= " + _TOSTR$(linenumber) + "; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars); if (*__LONG_VWATCH_GOTO>0) goto VWATCH_SETNEXTLINE; if (*__LONG_VWATCH_GOTO<0) goto VWATCH_SKIPLINE;"
                END IF
            END IF
            FOR i = controllevel TO 1 STEP -1
                t = controltype(i)
                IF t = 1 THEN
                    IF controlstate(controllevel) = 2 THEN a$ = "ELSEIF invalid after ELSE": GOTO errmes
                    controlstate(controllevel) = 1
                    controlvalue(controllevel) = controlvalue(controllevel) + 1
                    e$ = getelement$(a$, n)
                    IF e$ <> "THEN" THEN a$ = "Expected ELSEIF expression THEN": GOTO errmes
                    WriteBufLine MainTxtBuf, "}else{"
                    e$ = fixoperationorder$(getelements$(ca$, 2, n - 1))
                    IF Error_Happened THEN GOTO errmes
                    l$ = SCase$("ElseIf") + sp + tlayout$ + sp + SCase$("Then")
                    layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                    e$ = evaluate(e$, typ)
                    IF Error_Happened THEN GOTO errmes
                    IF (typ AND ISREFERENCE) THEN e$ = refer$(e$, typ, 0)
                    IF Error_Happened THEN GOTO errmes
                    IF typ AND ISSTRING THEN
                        a$ = "Expected ELSEIF LEN(stringexpression) THEN": GOTO errmes
                    END IF
                    IF stringprocessinghappened THEN
                        WriteBufLine MainTxtBuf, "if (" + cleanupstringprocessingcall$ + e$ + ")){"
                    ELSE
                        WriteBufLine MainTxtBuf, "if (" + e$ + "){"
                    END IF
                    lhscontrollevel = lhscontrollevel - 1
                    GOTO finishedline
                END IF
            NEXT
            a$ = "ELSEIF without IF": GOTO errmes
        END IF
    END IF

    IF n >= 3 THEN
        IF firstelement$ = "IF" THEN
            IF CheckingOn THEN
                WriteBufLine MainTxtBuf, "S_" + _TOSTR$(statementn) + ":;": dynscope = 1
                IF GetRCStateVar(vWatchOn) = 1 AND inclinenumber(inclevel) = 0 THEN
                    vWatchAddLabel linenumber, 0
                    WriteBufLine MainTxtBuf, "*__LONG_VWATCH_LINENUMBER= " + _TOSTR$(linenumber) + "; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars); if (*__LONG_VWATCH_GOTO>0) goto VWATCH_SETNEXTLINE; if (*__LONG_VWATCH_GOTO<0) goto VWATCH_SKIPLINE;"
                END IF
            END IF

            'prevents code from being placed before 'CASE condition' in a SELECT CASE block
            IF SelectCaseCounter > 0 AND SelectCaseHasCaseBlock(SelectCaseCounter) = 0 THEN
                a$ = "Expected CASE expression": GOTO errmes
            END IF

            e$ = getelement(a$, n)
            iftype = 0
            IF e$ = "THEN" THEN iftype = 1
            IF e$ = "GOTO" THEN iftype = 2
            IF iftype = 0 THEN a$ = "Expected IF expression THEN/GOTO": GOTO errmes

            controllevel = controllevel + 1
            controlref(controllevel) = linenumber
            controltype(controllevel) = 1
            controlvalue(controllevel) = 0 'number of extra closing } required at END IF
            controlstate(controllevel) = 0

            e$ = fixoperationorder$(getelements(ca$, 2, n - 1))
            IF Error_Happened THEN GOTO errmes
            l$ = SCase$("If") + sp + tlayout$
            e$ = evaluate(e$, typ)
            IF Error_Happened THEN GOTO errmes
            IF (typ AND ISREFERENCE) THEN e$ = refer$(e$, typ, 0)
            IF Error_Happened THEN GOTO errmes

            IF typ AND ISSTRING THEN
                a$ = "Expected IF LEN(stringexpression) THEN": GOTO errmes
            END IF

            IF stringprocessinghappened THEN
                WriteBufLine MainTxtBuf, "if ((" + cleanupstringprocessingcall$ + e$ + "))||is_error_pending()){"
            ELSE
                WriteBufLine MainTxtBuf, "if ((" + e$ + ")||is_error_pending()){"
            END IF

            IF iftype = 1 THEN l$ = l$ + sp + SCase$("Then") 'note: 'GOTO' will be added when iftype=2
            layoutdone = 1: IF LEN(layout$) = 0 THEN layout$ = l$ ELSE layout$ = layout$ + sp + l$

            IF iftype = 2 THEN 'IF ... GOTO
                GOTO finishedline
            END IF

            THENGOTO = 1 'possible: IF a=1 THEN 10
            GOTO finishedline2
        END IF
    END IF

    'ENDIF
    IF n = 1 AND getelement(a$, 1) = "ENDIF" THEN
        IF controltype(controllevel) <> 1 THEN a$ = "END IF without IF": GOTO errmes
        layoutdone = 1
        IF impliedendif = 0 THEN
            l$ = SCase$("End If")
            IF LEN(layout$) = 0 THEN layout$ = l$ ELSE layout$ = layout$ + sp + l$
        END IF

        WriteBufLine MainTxtBuf, "}"
        FOR i = 1 TO controlvalue(controllevel)
            WriteBufLine MainTxtBuf, "}"
        NEXT
        controllevel = controllevel - 1
        GOTO finishednonexec '***no error causing code, event checking done by IF***
    END IF


    'END IF
    IF n = 2 THEN
        IF getelement(a$, 1) = "END" AND getelement(a$, 2) = "IF" THEN


            IF controltype(controllevel) <> 1 THEN a$ = "END IF without IF": GOTO errmes
            layoutdone = 1
            IF impliedendif = 0 THEN
                l$ = SCase$("End" + sp + "If")
                IF LEN(layout$) = 0 THEN layout$ = l$ ELSE layout$ = layout$ + sp + l$
            END IF

            IF CheckingOn = 1 AND GetRCStateVar(vWatchOn) = 1 AND inclinenumber(inclevel) = 0 THEN
                vWatchAddLabel linenumber, 0
                WriteBufLine MainTxtBuf, "*__LONG_VWATCH_LINENUMBER= " + _TOSTR$(linenumber) + "; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars); if (*__LONG_VWATCH_GOTO>0) goto VWATCH_SETNEXTLINE; if (*__LONG_VWATCH_GOTO<0) goto VWATCH_SKIPLINE;"
            END IF

            WriteBufLine MainTxtBuf, "}"
            FOR i = 1 TO controlvalue(controllevel)
                WriteBufLine MainTxtBuf, "}"
            NEXT
            controllevel = controllevel - 1
            GOTO finishednonexec '***no error causing code, event checking done by IF***
        END IF
    END IF



    'SELECT CASE
    IF n >= 1 THEN
        IF firstelement$ = "SELECT" THEN
            IF CheckingOn THEN
                WriteBufLine MainTxtBuf, "S_" + _TOSTR$(statementn) + ":;": dynscope = 1
                IF GetRCStateVar(vWatchOn) = 1 AND inclinenumber(inclevel) = 0 THEN
                    vWatchAddLabel linenumber, 0
                    WriteBufLine MainTxtBuf, "*__LONG_VWATCH_LINENUMBER= " + _TOSTR$(linenumber) + "; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars); if (*__LONG_VWATCH_GOTO>0) goto VWATCH_SETNEXTLINE; if (*__LONG_VWATCH_GOTO<0) goto VWATCH_SKIPLINE;"
                END IF
            END IF

            'prevents code from being placed before 'CASE condition' in a SELECT CASE block
            IF SelectCaseCounter > 0 AND SelectCaseHasCaseBlock(SelectCaseCounter) = 0 THEN
                a$ = "Expected CASE expression": GOTO errmes
            END IF

            SelectCaseCounter = SelectCaseCounter + 1
            IF UBOUND(EveryCaseSet) <= SelectCaseCounter THEN REDIM _PRESERVE EveryCaseSet(SelectCaseCounter)
            IF UBOUND(SelectCaseHasCaseBlock) <= SelectCaseCounter THEN REDIM _PRESERVE SelectCaseHasCaseBlock(SelectCaseCounter)
            SelectCaseHasCaseBlock(SelectCaseCounter) = 0
            IF secondelement$ = "EVERYCASE" THEN
                EveryCaseSet(SelectCaseCounter) = -1
                IF n = 2 THEN a$ = "Expected SELECT CASE expression": GOTO errmes
                e$ = fixoperationorder(getelements$(ca$, 3, n))
                IF Error_Happened THEN GOTO errmes
                l$ = SCase$("Select EveryCase ") + tlayout$
            ELSE
                EveryCaseSet(SelectCaseCounter) = 0
                IF n = 1 OR secondelement$ <> "CASE" THEN a$ = "Expected CASE or EVERYCASE": GOTO errmes
                IF n = 2 THEN a$ = "Expected SELECT CASE expression": GOTO errmes
                e$ = fixoperationorder(getelements$(ca$, 3, n))
                IF Error_Happened THEN GOTO errmes
                l$ = SCase$("Select Case ") + tlayout$
            END IF

            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
            e$ = evaluate(e$, typ)
            IF Error_Happened THEN GOTO errmes
            u = uniquenumber

            controllevel = controllevel + 1
            controlvalue(controllevel) = 0 'id

            t$ = ""
            IF (typ AND ISSTRING) THEN
                t = 0
                IF (typ AND ISUDT) = 0 AND (typ AND ISARRAY) = 0 AND (typ AND ISREFERENCE) <> 0 THEN
                    controlvalue(controllevel) = VAL(e$)
                ELSE
                    IF (typ AND ISREFERENCE) THEN e$ = refer(e$, typ, 0)
                    IF Error_Happened THEN GOTO errmes
                    WriteBufLine DataTxtBuf, "static qbs *sc_" + _TOSTR$(u) + "=qbs_new(0,0);"
                    WriteBufLine MainTxtBuf, "qbs_set(sc_" + _TOSTR$(u) + "," + e$ + ");"
                    IF stringprocessinghappened THEN WriteBufLine MainTxtBuf, cleanupstringprocessingcall$ + "0);"
                END IF

            ELSE

                IF (typ AND ISFLOAT) THEN

                    IF (typ AND UDTMASK) > 64 THEN t = 3: t$ = "long double"
                    IF (typ AND UDTMASK) = 32 THEN t = 4: t$ = "float"
                    IF (typ AND UDTMASK) = 64 THEN t = 5: t$ = "double"
                    IF (typ AND ISUDT) = 0 AND (typ AND ISARRAY) = 0 AND (typ AND ISREFERENCE) <> 0 THEN
                        controlvalue(controllevel) = VAL(e$)
                    ELSE
                        IF (typ AND ISREFERENCE) THEN e$ = refer(e$, typ, 0)
                        IF Error_Happened THEN GOTO errmes

                        WriteBufLine DataTxtBuf, "static " + t$ + " sc_" + _TOSTR$(u) + ";"
                        WriteBufLine MainTxtBuf, "sc_" + _TOSTR$(u) + "=" + e$ + ";"
                        IF stringprocessinghappened THEN WriteBufLine MainTxtBuf, cleanupstringprocessingcall$ + "0);"
                    END IF

                ELSE

                    'non-float
                    t = 1: t$ = "int64"
                    IF (typ AND ISUNSIGNED) THEN
                        IF (typ AND UDTMASK) <= 32 THEN t = 7: t$ = "uint32"
                        IF (typ AND UDTMASK) > 32 THEN t = 2: t$ = "uint64"
                    ELSE
                        IF (typ AND UDTMASK) <= 32 THEN t = 6: t$ = "int32"
                        IF (typ AND UDTMASK) > 32 THEN t = 1: t$ = "int64"
                    END IF
                    IF (typ AND ISUDT) = 0 AND (typ AND ISARRAY) = 0 AND (typ AND ISREFERENCE) <> 0 THEN
                        controlvalue(controllevel) = VAL(e$)
                    ELSE
                        IF (typ AND ISREFERENCE) THEN e$ = refer(e$, typ, 0)
                        IF Error_Happened THEN GOTO errmes
                        WriteBufLine DataTxtBuf, "static " + t$ + " sc_" + _TOSTR$(u) + ";"
                        WriteBufLine MainTxtBuf, "sc_" + _TOSTR$(u) + "=" + e$ + ";"
                        IF stringprocessinghappened THEN WriteBufLine MainTxtBuf, cleanupstringprocessingcall$ + "0);"
                    END IF

                END IF
            END IF



            controlref(controllevel) = linenumber
            controltype(controllevel) = 10 + t
            controlid(controllevel) = u
            IF EveryCaseSet(SelectCaseCounter) THEN WriteBufLine DataTxtBuf, "int32 sc_" + _TOSTR$(controlid(controllevel)) + "_var;"
            IF EveryCaseSet(SelectCaseCounter) THEN WriteBufLine MainTxtBuf, "sc_" + _TOSTR$(controlid(controllevel)) + "_var=0;"
            GOTO finishedline
        END IF
    END IF


    'END SELECT
    IF n = 2 THEN
        IF firstelement$ = "END" AND secondelement$ = "SELECT" THEN
            'complete current case if necessary
            '18=CASE (awaiting END SELECT/CASE/CASE ELSE)
            '19=CASE ELSE (awaiting END SELECT)
            IF controltype(controllevel) = 18 THEN
                everycasenewcase = everycasenewcase + 1
                WriteBufLine MainTxtBuf, "sc_ec_" + _TOSTR$(everycasenewcase) + "_end:;"
                controllevel = controllevel - 1
                IF EveryCaseSet(SelectCaseCounter) = 0 THEN WriteBufLine MainTxtBuf, "goto sc_" + _TOSTR$(controlid(controllevel)) + "_end;"
                WriteBufLine MainTxtBuf, "}"
            END IF
            IF controltype(controllevel) = 19 THEN
                controllevel = controllevel - 1
                IF EveryCaseSet(SelectCaseCounter) THEN WriteBufLine MainTxtBuf, "} /* End of SELECT EVERYCASE ELSE */"
            END IF

            WriteBufLine MainTxtBuf, "sc_" + _TOSTR$(controlid(controllevel)) + "_end:;"
            IF controltype(controllevel) < 10 OR controltype(controllevel) > 17 THEN a$ = "END SELECT without SELECT CASE": GOTO errmes

            IF CheckingOn = 1 AND GetRCStateVar(vWatchOn) = 1 AND inclinenumber(inclevel) = 0 THEN
                vWatchAddLabel linenumber, 0
                WriteBufLine MainTxtBuf, "*__LONG_VWATCH_LINENUMBER= " + _TOSTR$(linenumber) + "; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars); if (*__LONG_VWATCH_GOTO>0) goto VWATCH_SETNEXTLINE; if (*__LONG_VWATCH_GOTO<0) goto VWATCH_SKIPLINE;"
            END IF

            IF SelectCaseCounter > 0 AND SelectCaseHasCaseBlock(SelectCaseCounter) = 0 THEN
                'warn user of empty SELECT CASE block
                IF NOT IgnoreWarnings THEN
                    addWarning linenumber, inclevel, inclinenumber(inclevel), incname$(inclevel), "Empty SELECT CASE block", ""
                END IF
            END IF

            controllevel = controllevel - 1
            SelectCaseCounter = SelectCaseCounter - 1
            l$ = SCase$("End" + sp + "Select")
            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
            GOTO finishednonexec '***no error causing code, event checking done by SELECT CASE***
        END IF
    END IF

    'prevents code from being placed before 'CASE condition' in a SELECT CASE block
    IF n >= 1 AND firstelement$ <> "CASE" AND SelectCaseCounter > 0 AND SelectCaseHasCaseBlock(SelectCaseCounter) = 0 THEN
        a$ = "Expected CASE expression": GOTO errmes
    END IF


    'CASE
    IF n >= 1 THEN
        IF firstelement$ = "CASE" THEN

            l$ = SCase$("Case")
            'complete current case if necessary
            '18=CASE (awaiting END SELECT/CASE/CASE ELSE)
            '19=CASE ELSE (awaiting END SELECT)
            IF controltype(controllevel) = 19 THEN a$ = "Expected END SELECT": GOTO errmes
            IF controltype(controllevel) = 18 THEN
                lhscontrollevel = lhscontrollevel - 1
                controllevel = controllevel - 1
                everycasenewcase = everycasenewcase + 1
                WriteBufLine MainTxtBuf, "sc_ec_" + _TOSTR$(everycasenewcase) + "_end:;"
                IF EveryCaseSet(SelectCaseCounter) = 0 THEN
                    WriteBufLine MainTxtBuf, "goto sc_" + _TOSTR$(controlid(controllevel)) + "_end;"
                ELSE
                    WriteBufLine MainTxtBuf, "sc_" + _TOSTR$(controlid(controllevel)) + "_var=-1;"
                END IF
                WriteBufLine MainTxtBuf, "}"
                'following line fixes problem related to RESUME after error
                'statementn = statementn + 1
                'if nochecks=0 then WriteBufLine MainTxtBuf, "S_" + _TOSTR$(statementn) + ":;"
            END IF

            IF controltype(controllevel) <> 6 AND (controltype(controllevel) < 10 OR controltype(controllevel) > 17) THEN a$ = "CASE without SELECT CASE": GOTO errmes
            IF n = 1 THEN a$ = "Expected CASE expression": GOTO errmes
            SelectCaseHasCaseBlock(SelectCaseCounter) = -1


            'upgrade:
            '#1: variables can be referred to directly by storing an id in 'controlref'
            '    (but not if part of an array etc.)
            'DIM controlvalue(1000) AS LONG
            '#2: more types will be available
            '    +SINGLE
            '    +DOUBLE
            '    -LONG DOUBLE
            '    +INT32
            '    +UINT32
            '14=SELECT CASE float ...
            '15=SELECT CASE double
            '16=SELECT CASE int32
            '17=SELECT CASE uint32

            '10=SELECT CASE qbs (awaiting END SELECT/CASE)
            '11=SELECT CASE int64 (awaiting END SELECT/CASE)
            '12=SELECT CASE uint64 (awaiting END SELECT/CASE)
            '13=SELECT CASE LONG double (awaiting END SELECT/CASE/CASE ELSE)
            '14=SELECT CASE float ...
            '15=SELECT CASE double
            '16=SELECT CASE int32
            '17=SELECT CASE uint32

            '    bits = targettyp AND UDTMASK
            '                                IF bits <= 16 THEN e$ = "qbr_float_to_long(" + e$ + ")"
            '                                IF bits > 16 AND bits < 32 THEN e$ = "qbr_double_to_long(" + e$ + ")"
            '                                IF bits >= 32 THEN e$ = "qbr(" + e$ + ")"


            t = controltype(controllevel) - 10
            'get required type cast, and float options
            flt = 0
            IF t = 0 THEN tc$ = ""
            IF t = 1 THEN tc$ = ""
            IF t = 2 THEN tc$ = ""
            IF t = 3 THEN tc$ = "": flt = 1
            IF t = 4 THEN tc$ = "(float)": flt = 1
            IF t = 5 THEN tc$ = "(double)": flt = 1
            IF t = 6 THEN tc$ = ""
            IF t = 7 THEN tc$ = ""

            n$ = "sc_" + _TOSTR$(controlid(controllevel))
            cv = controlvalue(controllevel)
            IF cv THEN
                n$ = refer$(_TOSTR$(cv), 0, 0)
                IF Error_Happened THEN GOTO errmes
            END IF

            'CASE ELSE
            IF n = 2 THEN
                IF getelement$(a$, 2) = "C-EL" THEN
                    IF EveryCaseSet(SelectCaseCounter) THEN WriteBufLine MainTxtBuf, "if (sc_" + _TOSTR$(controlid(controllevel)) + "_var==0) {"
                    controllevel = controllevel + 1: controltype(controllevel) = 19
                    controlref(controllevel) = controlref(controllevel - 1)
                    l$ = l$ + sp + SCase$("Else")
                    layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                    GOTO finishednonexec '***no error causing code, event checking done by SELECT CASE***
                END IF
            END IF

            IF CheckingOn THEN
                WriteBufLine MainTxtBuf, "S_" + _TOSTR$(statementn) + ":;": dynscope = 1
                IF GetRCStateVar(vWatchOn) = 1 AND inclinenumber(inclevel) = 0 THEN
                    vWatchAddLabel linenumber, 0
                    WriteBufLine MainTxtBuf, "*__LONG_VWATCH_LINENUMBER= " + _TOSTR$(linenumber) + "; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars); if (*__LONG_VWATCH_GOTO>0) goto VWATCH_SETNEXTLINE; if (*__LONG_VWATCH_GOTO<0) goto VWATCH_SKIPLINE;"
                END IF
            END IF



            f12$ = ""

            nexp = 0
            B = 0
            e$ = ""
            FOR i = 2 TO n
                e2$ = getelement$(ca$, i)
                IF e2$ = "(" THEN B = B + 1
                IF e2$ = ")" THEN B = B - 1
                IF i = n THEN e$ = e$ + sp + e2$
                IF i = n OR (e2$ = "," AND B = 0) THEN
                    IF nexp <> 0 THEN l$ = l$ + sp2 + ",": f12$ = f12$ + "||"
                    IF e$ = "" THEN a$ = "Expected expression": GOTO errmes
                    e$ = RIGHT$(e$, LEN(e$) - 1)



                    'TYPE 1? ... TO ...
                    n2 = numelements(e$)
                    b2 = 0
                    el$ = "": er$ = ""
                    usedto = 0
                    FOR i2 = 1 TO n2
                        e3$ = getelement$(e$, i2)
                        IF e3$ = "(" THEN b2 = b2 + 1
                        IF e3$ = ")" THEN b2 = b2 - 1
                        IF b2 = 0 AND UCASE$(e3$) = "TO" THEN
                            usedto = 1
                        ELSE
                            IF usedto = 0 THEN el$ = el$ + sp + e3$ ELSE er$ = er$ + sp + e3$
                        END IF
                    NEXT
                    IF usedto = 1 THEN
                        IF el$ = "" OR er$ = "" THEN a$ = "Expected expression TO expression": GOTO errmes
                        el$ = RIGHT$(el$, LEN(el$) - 1): er$ = RIGHT$(er$, LEN(er$) - 1)
                        'evaluate each side
                        FOR i2 = 1 TO 2
                            IF i2 = 1 THEN e$ = el$ ELSE e$ = er$
                            e$ = fixoperationorder(e$)
                            IF Error_Happened THEN GOTO errmes
                            IF i2 = 1 THEN l$ = l$ + sp + tlayout$ ELSE l$ = l$ + sp + SCase$("To") + sp + tlayout$
                            e$ = evaluate(e$, typ)
                            IF Error_Happened THEN GOTO errmes
                            IF (typ AND ISREFERENCE) THEN e$ = refer(e$, typ, 0)
                            IF Error_Happened THEN GOTO errmes
                            IF t = 0 THEN
                                IF (typ AND ISSTRING) = 0 THEN a$ = "Expected string expression": GOTO errmes
                                IF i2 = 1 THEN f12$ = f12$ + "(qbs_greaterorequal(" + n$ + "," + e$ + ")&&qbs_lessorequal(" + n$ + ","
                                IF i2 = 2 THEN f12$ = f12$ + e$ + "))"
                            ELSE
                                IF (typ AND ISSTRING) THEN a$ = "Expected numeric expression": GOTO errmes
                                'round to integer?
                                IF (typ AND ISFLOAT) THEN
                                    IF t = 1 THEN e$ = "qbr(" + e$ + ")"
                                    IF t = 2 THEN e$ = "qbr_longdouble_to_uint64(" + e$ + ")"
                                    IF t = 6 OR t = 7 THEN e$ = "qbr_double_to_long(" + e$ + ")"
                                END IF
                                'cast result?
                                IF LEN(tc$) THEN e$ = tc$ + "(" + e$ + ")"
                                IF i2 = 1 THEN f12$ = f12$ + "((" + n$ + ">=(" + e$ + "))&&(" + n$ + "<=("
                                IF i2 = 2 THEN f12$ = f12$ + e$ + ")))"
                            END IF
                        NEXT
                        GOTO addedexp
                    END IF

                    '10=SELECT CASE qbs (awaiting END SELECT/CASE)
                    '11=SELECT CASE int64 (awaiting END SELECT/CASE)
                    '12=SELECT CASE uint64 (awaiting END SELECT/CASE)
                    '13=SELECT CASE LONG double (awaiting END SELECT/CASE/CASE ELSE)
                    '14=SELECT CASE float ...
                    '15=SELECT CASE double
                    '16=SELECT CASE int32
                    '17=SELECT CASE uint32

                    '    bits = targettyp AND UDTMASK
                    '                                IF bits <= 16 THEN e$ = "qbr_float_to_long(" + e$ + ")"
                    '                                IF bits > 16 AND bits < 32 THEN e$ = "qbr_double_to_long(" + e$ + ")"
                    '                                IF bits >= 32 THEN e$ = "qbr(" + e$ + ")"






                    o$ = "==" 'used by type 3

                    'TYPE 2?
                    x$ = getelement$(e$, 1)
                    IF isoperator(x$) THEN 'non-standard usage correction
                        IF x$ = "=" OR x$ = "<>" OR x$ = ">" OR x$ = "<" OR x$ = ">=" OR x$ = "<=" THEN
                            e$ = "IS" + sp + e$
                            x$ = "IS"
                        END IF
                    END IF
                    IF UCASE$(x$) = "IS" THEN
                        n2 = numelements(e$)
                        IF n2 < 3 THEN a$ = "Expected IS =,<>,>,<,>=,<= expression": GOTO errmes
                        o$ = getelement$(e$, 2)
                        o2$ = o$
                        o = 0
                        IF o$ = "=" THEN o$ = "==": o = 1
                        IF o$ = "<>" THEN o$ = "!=": o = 1
                        IF o$ = ">" THEN o = 1
                        IF o$ = "<" THEN o = 1
                        IF o$ = ">=" THEN o = 1
                        IF o$ = "<=" THEN o = 1
                        IF o <> 1 THEN a$ = "Expected IS =,<>,>,<,>=,<= expression": GOTO errmes
                        l$ = l$ + sp + SCase$("Is") + sp + o2$
                        e$ = getelements$(e$, 3, n2)
                        'fall through to type 3 using modified e$ & o$
                    END IF

                    'TYPE 3? simple expression
                    e$ = fixoperationorder(e$)
                    IF Error_Happened THEN GOTO errmes
                    l$ = l$ + sp + tlayout$
                    e$ = evaluate(e$, typ)
                    IF Error_Happened THEN GOTO errmes
                    IF (typ AND ISREFERENCE) THEN e$ = refer(e$, typ, 0)
                    IF Error_Happened THEN GOTO errmes
                    IF t = 0 THEN
                        'string comparison
                        IF (typ AND ISSTRING) = 0 THEN a$ = "Expected string expression": GOTO errmes
                        IF o$ = "==" THEN o$ = "qbs_equal"
                        IF o$ = "!=" THEN o$ = "qbs_notequal"
                        IF o$ = ">" THEN o$ = "qbs_greaterthan"
                        IF o$ = "<" THEN o$ = "qbs_lessthan"
                        IF o$ = ">=" THEN o$ = "qbs_greaterorequal"
                        IF o$ = "<=" THEN o$ = "qbs_lessorequal"
                        f12$ = f12$ + o$ + "(" + n$ + "," + e$ + ")"
                    ELSE
                        'numeric
                        IF (typ AND ISSTRING) THEN a$ = "Expected numeric expression": GOTO errmes
                        'round to integer?
                        IF (typ AND ISFLOAT) THEN
                            IF t = 1 THEN e$ = "qbr(" + e$ + ")"
                            IF t = 2 THEN e$ = "qbr_longdouble_to_uint64(" + e$ + ")"
                            IF t = 6 OR t = 7 THEN e$ = "qbr_double_to_long(" + e$ + ")"
                        END IF
                        'cast result?
                        IF LEN(tc$) THEN e$ = tc$ + "(" + e$ + ")"
                        f12$ = f12$ + "(" + n$ + o$ + "(" + e$ + "))"
                    END IF

                    addedexp:
                    e$ = ""
                    nexp = nexp + 1
                ELSE
                    e$ = e$ + sp + e2$
                END IF
            NEXT

            IF stringprocessinghappened THEN
                WriteBufLine MainTxtBuf, "if ((" + cleanupstringprocessingcall$ + f12$ + "))||is_error_pending()){"
            ELSE
                WriteBufLine MainTxtBuf, "if ((" + f12$ + ")||is_error_pending()){"
            END IF

            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
            controllevel = controllevel + 1
            controlref(controllevel) = controlref(controllevel - 1)
            controltype(controllevel) = 18
            GOTO finishedline
        END IF
    END IF












    'static scope commands:

    IF CheckingOn THEN
        IF GetRCStateVar(vWatchOn) = 1 AND inclinenumber(inclevel) = 0 THEN
            vWatchAddLabel linenumber, 0
            WriteBufLine MainTxtBuf, "do{*__LONG_VWATCH_LINENUMBER= " + _TOSTR$(linenumber) + "; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars); if (*__LONG_VWATCH_GOTO>0) goto VWATCH_SETNEXTLINE; if (*__LONG_VWATCH_GOTO<0) goto VWATCH_SKIPLINE;"
        ELSE
            WriteBufLine MainTxtBuf, "do{"
        END IF
        'WriteBufLine MainTxtBuf, "S_" + _TOSTR$(statementn) + ":;"
    END IF


    IF n > 1 THEN
        IF firstelement$ = "PALETTE" THEN
            IF secondelement$ = "USING" THEN
                l$ = SCase$("Palette" + sp + "Using" + sp)
                IF n < 3 THEN a$ = "Expected PALETTE USING array-name": GOTO errmes
                'check array
                e$ = getelement$(ca$, 3)
                IF FindArray(e$) THEN
                    IF Error_Happened THEN GOTO errmes
                    z = 1
                    t = id.arraytype
                    IF (t AND UDTMASK) <> 16 AND (t AND UDTMASK) <> 32 THEN z = 0
                    IF t AND ISFLOAT THEN z = 0
                    IF t AND ISOFFSETINBITS THEN z = 0
                    IF t AND ISSTRING THEN z = 0
                    IF t AND ISUDT THEN z = 0
                    IF t AND ISUNSIGNED THEN z = 0
                    IF z = 0 THEN a$ = "Array must be of type INTEGER or LONG": GOTO errmes
                    bits = t AND UDTMASK
                    GOTO pu_gotarray
                END IF
                IF Error_Happened THEN GOTO errmes
                a$ = "Expected PALETTE USING array-name": GOTO errmes
                pu_gotarray:
                'add () if index not specified
                IF n = 3 THEN
                    e$ = e$ + sp + "(" + sp + ")"
                ELSE
                    IF n = 4 OR getelement$(a$, 4) <> "(" OR getelement$(a$, n) <> ")" THEN a$ = "Expected PALETTE USING array-name(...)": GOTO errmes
                    e$ = e$ + sp + getelements$(ca$, 4, n)
                END IF
                e$ = fixoperationorder$(e$)
                IF Error_Happened THEN GOTO errmes
                l$ = l$ + tlayout$
                e$ = evaluatetotyp(e$, -2)
                IF Error_Happened THEN GOTO errmes
                WriteBufLine MainTxtBuf, "sub_paletteusing(" + e$ + "," + _TOSTR$(bits) + ");"
                layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                GOTO finishedline
            END IF 'using
        END IF 'palette
    END IF 'n>1


    IF firstelement$ = "KEY" THEN
        IF n = 1 THEN a$ = "Expected KEY ...": GOTO errmes
        l$ = SCase$("Key") + sp
        IF secondelement$ = "OFF" THEN
            IF n > 2 THEN a$ = "Expected KEY OFF only": GOTO errmes
            l$ = l$ + SCase$("Off"): layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
            WriteBufLine MainTxtBuf, "key_off();"
            GOTO finishedline
        END IF
        IF secondelement$ = "ON" THEN
            IF n > 2 THEN a$ = "Expected KEY ON only": GOTO errmes
            l$ = l$ + SCase$("On"): layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
            WriteBufLine MainTxtBuf, "key_on();"
            GOTO finishedline
        END IF
        IF secondelement$ = "LIST" THEN
            IF n > 2 THEN a$ = "Expected KEY LIST only": GOTO errmes
            l$ = l$ + SCase$("List"): layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
            WriteBufLine MainTxtBuf, "key_list();"
            GOTO finishedline
        END IF
        'search for comma to indicate assignment
        B = 0: e$ = ""
        FOR i = 2 TO n
            e2$ = getelement(ca$, i)
            IF e2$ = "(" THEN B = B + 1
            IF e2$ = ")" THEN B = B - 1
            IF e2$ = "," AND B = 0 THEN
                i = i + 1: GOTO key_assignment
            END IF
            IF LEN(e$) THEN e$ = e$ + sp + e2$ ELSE e$ = e2$
        NEXT
        'assume KEY(x) ON/OFF/STOP and handle as a sub
        GOTO key_fallthrough
        key_assignment:
        'KEY x, "string"
        'index
        e$ = fixoperationorder(e$)
        IF Error_Happened THEN GOTO errmes
        l$ = l$ + tlayout$ + sp2 + "," + sp
        e$ = evaluatetotyp(e$, 32&)
        IF Error_Happened THEN GOTO errmes
        WriteBufRawData MainTxtBuf, "key_assign(" + e$ + ","
        'string
        e$ = getelements$(ca$, i, n)
        e$ = fixoperationorder(e$)
        IF Error_Happened THEN GOTO errmes
        l$ = l$ + tlayout$
        e$ = evaluatetotyp(e$, ISSTRING)
        IF Error_Happened THEN GOTO errmes
        WriteBufLine MainTxtBuf, e$ + ");"
        layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
        GOTO finishedline
    END IF 'KEY
    key_fallthrough:




    IF firstelement$ = "FIELD" THEN

        'get filenumber
        B = 0: e$ = ""
        FOR i = 2 TO n
            e2$ = getelement(ca$, i)
            IF e2$ = "(" THEN B = B + 1
            IF e2$ = ")" THEN B = B - 1
            IF e2$ = "," AND B = 0 THEN
                i = i + 1: GOTO fieldgotfn
            END IF
            IF LEN(e$) THEN e$ = e$ + sp + e2$ ELSE e$ = e2$
        NEXT
        GOTO fielderror
        fieldgotfn:
        IF e$ = "#" OR LEN(e$) = 0 THEN GOTO fielderror
        IF LEFT$(e$, 2) = "#" + sp THEN e$ = RIGHT$(e$, LEN(e$) - 2): l$ = SCase$("Field") + sp + "#" + sp2 ELSE l$ = SCase$("Field") + sp
        e$ = fixoperationorder(e$)
        IF Error_Happened THEN GOTO errmes
        l$ = l$ + tlayout$ + sp2 + "," + sp
        e$ = evaluatetotyp(e$, 32&)
        IF Error_Happened THEN GOTO errmes
        WriteBufLine MainTxtBuf, "field_new(" + e$ + ");"

        fieldnext:

        'get fieldwidth
        IF i > n THEN GOTO fielderror
        B = 0: e$ = ""
        FOR i = i TO n
            e2$ = getelement(ca$, i)
            IF e2$ = "(" THEN B = B + 1
            IF e2$ = ")" THEN B = B - 1
            IF UCASE$(e2$) = "AS" AND B = 0 THEN
                i = i + 1: GOTO fieldgotfw
            END IF
            IF LEN(e$) THEN e$ = e$ + sp + e2$ ELSE e$ = e2$
        NEXT
        GOTO fielderror
        fieldgotfw:
        IF LEN(e$) = 0 THEN GOTO fielderror
        e$ = fixoperationorder(e$)
        IF Error_Happened THEN GOTO errmes
        l$ = l$ + tlayout$ + sp + SCase$("As") + sp
        sizee$ = evaluatetotyp(e$, 32&)
        IF Error_Happened THEN GOTO errmes

        'get variable name
        IF i > n THEN GOTO fielderror
        B = 0: e$ = ""
        FOR i = i TO n
            e2$ = getelement(ca$, i)
            IF e2$ = "(" THEN B = B + 1
            IF e2$ = ")" THEN B = B - 1
            IF (i = n OR e2$ = ",") AND B = 0 THEN
                IF e2$ = "," THEN i = i - 1
                IF i = n THEN
                    IF LEN(e$) THEN e$ = e$ + sp + e2$ ELSE e$ = e2$
                END IF
                GOTO fieldgotfname
            END IF
            IF LEN(e$) THEN e$ = e$ + sp + e2$ ELSE e$ = e2$
        NEXT
        GOTO fielderror
        fieldgotfname:
        IF LEN(e$) = 0 THEN GOTO fielderror
        'evaluate it to check it is a STRING
        e$ = fixoperationorder(e$)
        IF Error_Happened THEN GOTO errmes
        l$ = l$ + tlayout$
        e$ = evaluate(e$, typ)
        IF Error_Happened THEN GOTO errmes
        IF (typ AND ISSTRING) = 0 THEN GOTO fielderror
        IF typ AND ISFIXEDLENGTH THEN a$ = "Fixed length strings cannot be used in a FIELD statement": GOTO errmes
        IF (typ AND ISREFERENCE) = 0 THEN GOTO fielderror
        e$ = refer(e$, typ, 0)
        IF Error_Happened THEN GOTO errmes
        WriteBufLine MainTxtBuf, "field_add(" + e$ + "," + sizee$ + ");"

        IF i < n THEN
            i = i + 1
            e$ = getelement(a$, i)
            IF e$ <> "," THEN a$ = "Expected ,": GOTO errmes
            l$ = l$ + sp2 + "," + sp
            i = i + 1
            GOTO fieldnext
        END IF

        layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
        GOTO finishedline

        fielderror: a$ = "Expected FIELD #filenumber, characters AS variable$, ...": GOTO errmes
    END IF





    '1=IF (awaiting END IF)
    '2=FOR (awaiting NEXT)
    '3=DO (awaiting LOOP [UNTIL|WHILE param])
    '4=DO WHILE/UNTIL (awaiting LOOP)
    '5=WHILE (awaiting WEND)

    IF n = 2 THEN
        IF firstelement$ = "EXIT" THEN

            l$ = SCase$("Exit") + sp

            IF secondelement$ = "DO" THEN
                'scan backwards until previous control level reached
                l$ = l$ + SCase$("Do")
                FOR i = controllevel TO 1 STEP -1
                    t = controltype(i)
                    IF t = 3 OR t = 4 THEN
                        WriteBufLine MainTxtBuf, "goto dl_exit_" + _TOSTR$(controlid(i)) + ";"
                        layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                        GOTO finishedline
                    END IF
                NEXT
                a$ = "EXIT DO without DO": GOTO errmes
            END IF

            IF secondelement$ = "FOR" THEN
                'scan backwards until previous control level reached
                l$ = l$ + SCase$("For")
                FOR i = controllevel TO 1 STEP -1
                    t = controltype(i)
                    IF t = 2 THEN
                        WriteBufLine MainTxtBuf, "goto fornext_exit_" + _TOSTR$(controlid(i)) + ";"
                        layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                        GOTO finishedline
                    END IF
                NEXT
                a$ = "EXIT FOR without FOR": GOTO errmes
            END IF

            IF secondelement$ = "WHILE" THEN
                'scan backwards until previous control level reached
                l$ = l$ + SCase$("While")
                FOR i = controllevel TO 1 STEP -1
                    t = controltype(i)
                    IF t = 5 THEN
                        WriteBufLine MainTxtBuf, "goto ww_exit_" + _TOSTR$(controlid(i)) + ";"
                        layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                        GOTO finishedline
                    END IF
                NEXT
                a$ = "EXIT WHILE without WHILE": GOTO errmes
            END IF

            IF secondelement$ = "SELECT" THEN
                'scan backwards until previous control level reached
                l$ = l$ + SCase$("Select")
                FOR i = controllevel TO 1 STEP -1
                    t = controltype(i)
                    IF t = 18 OR t = 19 THEN 'CASE/CASE ELSE
                        WriteBufLine MainTxtBuf, "goto sc_" + _TOSTR$(controlid(i - 1)) + "_end;"
                        layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                        GOTO finishedline
                    END IF
                NEXT
                a$ = "EXIT SELECT without SELECT": GOTO errmes
            END IF

            IF secondelement$ = "CASE" THEN
                'scan backwards until previous control level reached
                l$ = l$ + SCase$("Case")
                FOR i = controllevel TO 1 STEP -1
                    t = controltype(i)
                    IF t = 18 THEN 'CASE
                        WriteBufLine MainTxtBuf, "goto sc_ec_" + _TOSTR$(everycasenewcase + 1) + "_end;"
                        layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                        GOTO finishedline
                    ELSEIF t = 19 THEN 'CASE ELSE
                        WriteBufLine MainTxtBuf, "goto sc_" + _TOSTR$(controlid(i - 1)) + "_end;"
                        layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                        GOTO finishedline
                    END IF
                NEXT
                a$ = "EXIT CASE without CASE": GOTO errmes
            END IF

        END IF
    END IF








    IF n >= 2 THEN
        IF firstelement$ = "ON" AND secondelement$ = "STRIG" THEN
            SetDependency DEPENDENCY_DEVICEINPUT
            i = 3
            IF i > n THEN a$ = "Expected (": GOTO errmes
            a2$ = getelement$(ca$, i): i = i + 1
            IF a2$ <> "(" THEN a$ = "Expected (": GOTO errmes
            l$ = SCase$("On" + sp + "Strig" + sp2 + "(")
            IF i > n THEN a$ = "Expected ...": GOTO errmes
            B = 0
            x = 0
            e2$ = ""
            e3$ = ""
            FOR i = i TO n
                e$ = getelement$(ca$, i)
                a = ASC(e$)
                IF a = 40 THEN B = B + 1
                IF a = 41 THEN B = B - 1
                IF B = -1 THEN GOTO onstriggotarg
                IF a = 44 AND B = 0 THEN
                    x = x + 1
                    IF x > 1 THEN a$ = "Expected )": GOTO errmes
                    IF e2$ = "" THEN a$ = "Expected ... ,": GOTO errmes
                    e3$ = e2$
                    e2$ = ""
                ELSE
                    IF LEN(e2$) THEN e2$ = e2$ + sp + e$ ELSE e2$ = e$
                END IF
            NEXT
            a$ = "Expected )": GOTO errmes
            onstriggotarg:
            IF e2$ = "" THEN a$ = "Expected ... )": GOTO errmes
            WriteBufRawData MainTxtBuf, "onstrig_setup("

            'sort scanned results
            IF LEN(e3$) THEN
                optI$ = e3$
                optController$ = e2$
                optPassed$ = "1"
            ELSE
                optI$ = e2$
                optController$ = "0"
                optPassed$ = "0"
            END IF

            'i
            e$ = fixoperationorder$(optI$): IF Error_Happened THEN GOTO errmes
            l$ = l$ + sp2 + tlayout$
            e$ = evaluatetotyp(e$, 32&): IF Error_Happened THEN GOTO errmes
            WriteBufRawData MainTxtBuf, e$ + ","

            'controller , passed
            IF optPassed$ = "1" THEN
                e$ = fixoperationorder$(optController$): IF Error_Happened THEN GOTO errmes
                l$ = l$ + sp2 + "," + sp + tlayout$
                e$ = evaluatetotyp(e$, 32&): IF Error_Happened THEN GOTO errmes
            ELSE
                e$ = optController$
            END IF
            WriteBufRawData MainTxtBuf, e$ + "," + optPassed$ + ","

            l$ = l$ + sp2 + ")" + sp 'close brackets

            i = i + 1
            IF i > n THEN a$ = "Expected GOSUB/sub-name": GOTO errmes
            a2$ = getelement$(a$, i): i = i + 1
            onstrigid = onstrigid + 1
            WriteBufRawData MainTxtBuf, _TOSTR$(onstrigid) + ","

            IF a2$ = "GOSUB" THEN
                IF i > n THEN a$ = "Expected linenumber/label": GOTO errmes
                a2$ = getelement$(ca$, i): i = i + 1

                WriteBufLine MainTxtBuf, "0);"

                IF validlabel(a2$) = 0 THEN a$ = "Invalid label": GOTO errmes

                v = HashFind(a2$, HASHFLAG_LABEL, ignore, r)
                x = 1
                labchk60z:
                IF v THEN
                    s = Labels(r).Scope
                    IF s = 0 OR s = -1 THEN 'main scope?
                        IF s = -1 THEN Labels(r).Scope = 0 'acquire scope
                        x = 0 'already defined
                        tlayout$ = RTRIM$(Labels(r).cn)
                        Labels(r).Scope_Restriction = subfuncn
                        Labels(r).Error_Line = linenumber
                    ELSE
                        IF v = 2 THEN v = HashFindCont(ignore, r): GOTO labchk60z
                    END IF
                END IF
                IF x THEN
                    'does not exist
                    nLabels = nLabels + 1: IF nLabels > Labels_Ubound THEN Labels_Ubound = Labels_Ubound * 2: REDIM _PRESERVE Labels(1 TO Labels_Ubound) AS Label_Type
                    Labels(nLabels) = Empty_Label
                    HashAdd a2$, HASHFLAG_LABEL, nLabels
                    r = nLabels
                    Labels(r).State = 0
                    Labels(r).cn = tlayout$
                    Labels(r).Scope = 0
                    Labels(r).Error_Line = linenumber
                    Labels(r).Scope_Restriction = subfuncn
                END IF 'x
                l$ = l$ + SCase$("GoSub") + sp + tlayout$

                WriteBufLine StrigjTxtBuf, "if(strig_event_id==" + _TOSTR$(onstrigid) + ")goto LABEL_" + a2$ + ";"

                WriteBufLine StrigTxtBuf, "case " + _TOSTR$(onstrigid) + ":"
                WriteBufLine StrigTxtBuf, "strig_event_occurred++;"
                WriteBufLine StrigTxtBuf, "strig_event_id=" + _TOSTR$(onstrigid) + ";"
                WriteBufLine StrigTxtBuf, "strig_event_occurred++;"
                WriteBufLine StrigTxtBuf, "return_point[next_return_point++]=0;"
                WriteBufLine StrigTxtBuf, "if (next_return_point>=return_points) more_return_points();"
                WriteBufLine StrigTxtBuf, "QBMAIN(NULL);"
                WriteBufLine StrigTxtBuf, "break;"

                IF LEN(layout$) = 0 THEN layout$ = l$ ELSE layout$ = layout$ + sp + l$
                layoutdone = 1
                GOTO finishedline

            ELSE

                'establish whether sub a2$ exists using try
                x = 0
                try = findid(a2$)
                IF Error_Happened THEN GOTO errmes
                DO WHILE try
                    IF id.subfunc = 2 THEN x = 1: EXIT DO
                    IF try = 2 THEN findanotherid = 1: try = findid(a2$) ELSE try = 0
                    IF Error_Happened THEN GOTO errmes
                LOOP
                IF x = 0 THEN a$ = "Expected GOSUB/sub": GOTO errmes

                l$ = l$ + RTRIM$(id.cn)

                WriteBufLine StrigTxtBuf, "case " + _TOSTR$(onstrigid) + ":"
                WriteBufRawData StrigTxtBuf, RTRIM$(id.callname) + "("

                IF id.args > 1 THEN a$ = "SUB requires more than one argument": GOTO errmes

                IF i > n THEN

                    IF id.args = 1 THEN a$ = "Expected argument after SUB": GOTO errmes
                    WriteBufLine MainTxtBuf, "0);"
                    WriteBufLine StrigTxtBuf, ");"

                ELSE

                    IF id.args = 0 THEN a$ = "SUB has no arguments": GOTO errmes

                    t = CVL(id.arg)
                    B = t AND UDTMASK
                    IF B = 0 OR (t AND ISARRAY) <> 0 OR (t AND ISFLOAT) <> 0 OR (t AND ISSTRING) <> 0 OR (t AND ISOFFSETINBITS) <> 0 THEN a$ = "Only SUB arguments of integer-type allowed": GOTO errmes
                    IF B = 8 THEN ct$ = "int8"
                    IF B = 16 THEN ct$ = "int16"
                    IF B = 32 THEN ct$ = "int32"
                    IF B = 64 THEN ct$ = "int64"
                    IF t AND ISOFFSET THEN ct$ = "ptrszint"
                    IF t AND ISUNSIGNED THEN ct$ = "u" + ct$
                    WriteBufLine StrigTxtBuf, "(" + ct$ + "*)&i64);"

                    e$ = getelements$(ca$, i, n)
                    e$ = fixoperationorder$(e$)
                    IF Error_Happened THEN GOTO errmes
                    l$ = l$ + sp + tlayout$
                    e$ = evaluatetotyp(e$, INTEGER64TYPE - ISPOINTER)
                    IF Error_Happened THEN GOTO errmes
                    WriteBufLine MainTxtBuf, e$ + ");"

                END IF

                WriteBufLine StrigTxtBuf, "break;"
                IF LEN(layout$) = 0 THEN layout$ = l$ ELSE layout$ = layout$ + sp + l$
                layoutdone = 1
                GOTO finishedline
            END IF

        END IF
    END IF












    IF n >= 2 THEN
        IF firstelement$ = "ON" AND secondelement$ = "TIMER" THEN
            i = 3
            IF i > n THEN a$ = "Expected (": GOTO errmes
            a2$ = getelement$(ca$, i): i = i + 1
            IF a2$ <> "(" THEN a$ = "Expected (": GOTO errmes
            l$ = SCase$("On" + sp + "Timer" + sp2 + "(")
            IF i > n THEN a$ = "Expected ...": GOTO errmes
            B = 0
            x = 0
            e2$ = ""
            e3$ = ""
            FOR i = i TO n
                e$ = getelement$(ca$, i)
                a = ASC(e$)
                IF a = 40 THEN B = B + 1
                IF a = 41 THEN B = B - 1
                IF B = -1 THEN GOTO ontimgotarg
                IF a = 44 AND B = 0 THEN
                    x = x + 1
                    IF x > 1 THEN a$ = "Expected )": GOTO errmes
                    IF e2$ = "" THEN a$ = "Expected ... ,": GOTO errmes
                    e3$ = e2$
                    e2$ = ""
                ELSE
                    IF LEN(e2$) THEN e2$ = e2$ + sp + e$ ELSE e2$ = e$
                END IF
            NEXT
            a$ = "Expected )": GOTO errmes
            ontimgotarg:
            IF e2$ = "" THEN a$ = "Expected ... )": GOTO errmes
            WriteBufRawData MainTxtBuf, "ontimer_setup("
            'i
            IF LEN(e3$) THEN
                e$ = fixoperationorder$(e3$)
                IF Error_Happened THEN GOTO errmes
                l$ = l$ + sp2 + tlayout$ + "," + sp
                e$ = evaluatetotyp(e$, 32&)
                IF Error_Happened THEN GOTO errmes
                WriteBufRawData MainTxtBuf, e$ + ","
            ELSE
                WriteBufRawData MainTxtBuf, "0,"
                l$ = l$ + sp2
            END IF
            'sec
            e$ = fixoperationorder$(e2$)
            IF Error_Happened THEN GOTO errmes
            l$ = l$ + tlayout$ + sp2 + ")" + sp
            e$ = evaluatetotyp(e$, DOUBLETYPE - ISPOINTER)
            IF Error_Happened THEN GOTO errmes
            WriteBufRawData MainTxtBuf, e$ + ","
            i = i + 1
            IF i > n THEN a$ = "Expected GOSUB/sub-name": GOTO errmes
            a2$ = getelement$(a$, i): i = i + 1
            ontimerid = ontimerid + 1
            WriteBufRawData MainTxtBuf, _TOSTR$(ontimerid) + ","

            IF a2$ = "GOSUB" THEN
                IF i > n THEN a$ = "Expected linenumber/label": GOTO errmes
                a2$ = getelement$(ca$, i): i = i + 1

                WriteBufLine MainTxtBuf, "0);"

                IF validlabel(a2$) = 0 THEN a$ = "Invalid label": GOTO errmes

                v = HashFind(a2$, HASHFLAG_LABEL, ignore, r)
                x = 1
                labchk60:
                IF v THEN
                    s = Labels(r).Scope
                    IF s = 0 OR s = -1 THEN 'main scope?
                        IF s = -1 THEN Labels(r).Scope = 0 'acquire scope
                        x = 0 'already defined
                        tlayout$ = RTRIM$(Labels(r).cn)
                        Labels(r).Scope_Restriction = subfuncn
                        Labels(r).Error_Line = linenumber
                    ELSE
                        IF v = 2 THEN v = HashFindCont(ignore, r): GOTO labchk60
                    END IF
                END IF
                IF x THEN
                    'does not exist
                    nLabels = nLabels + 1: IF nLabels > Labels_Ubound THEN Labels_Ubound = Labels_Ubound * 2: REDIM _PRESERVE Labels(1 TO Labels_Ubound) AS Label_Type
                    Labels(nLabels) = Empty_Label
                    HashAdd a2$, HASHFLAG_LABEL, nLabels
                    r = nLabels
                    Labels(r).State = 0
                    Labels(r).cn = tlayout$
                    Labels(r).Scope = 0
                    Labels(r).Error_Line = linenumber
                    Labels(r).Scope_Restriction = subfuncn
                END IF 'x
                l$ = l$ + SCase$("GoSub") + sp + tlayout$

                WriteBufLine TimejTxtBuf, "if(timer_event_id==" + _TOSTR$(ontimerid) + ")goto LABEL_" + a2$ + ";"

                WriteBufLine TimeTxtBuf, "case " + _TOSTR$(ontimerid) + ":"
                WriteBufLine TimeTxtBuf, "timer_event_occurred++;"
                WriteBufLine TimeTxtBuf, "timer_event_id=" + _TOSTR$(ontimerid) + ";"
                WriteBufLine TimeTxtBuf, "timer_event_occurred++;"
                WriteBufLine TimeTxtBuf, "return_point[next_return_point++]=0;"
                WriteBufLine TimeTxtBuf, "if (next_return_point>=return_points) more_return_points();"
                WriteBufLine TimeTxtBuf, "QBMAIN(NULL);"
                WriteBufLine TimeTxtBuf, "break;"



                'call validlabel (to validate the label) [see goto]
                'increment ontimerid
                'use ontimerid to generate the jumper routine
                'etc.


                IF LEN(layout$) = 0 THEN layout$ = l$ ELSE layout$ = layout$ + sp + l$
                layoutdone = 1
                GOTO finishedline
            ELSE

                'establish whether sub a2$ exists using try
                x = 0
                try = findid(a2$)
                IF Error_Happened THEN GOTO errmes
                DO WHILE try
                    IF id.subfunc = 2 THEN x = 1: EXIT DO
                    IF try = 2 THEN findanotherid = 1: try = findid(a2$) ELSE try = 0
                    IF Error_Happened THEN GOTO errmes
                LOOP
                IF x = 0 THEN a$ = "Expected GOSUB/sub": GOTO errmes

                l$ = l$ + RTRIM$(id.cn)

                WriteBufLine TimeTxtBuf, "case " + _TOSTR$(ontimerid) + ":"
                WriteBufRawData TimeTxtBuf, RTRIM$(id.callname) + "("

                IF id.args > 1 THEN a$ = "SUB requires more than one argument": GOTO errmes

                IF i > n THEN

                    IF id.args = 1 THEN a$ = "Expected argument after SUB": GOTO errmes
                    WriteBufLine MainTxtBuf, "0);"
                    WriteBufLine TimeTxtBuf, ");"

                ELSE

                    IF id.args = 0 THEN a$ = "SUB has no arguments": GOTO errmes

                    t = CVL(id.arg)
                    B = t AND UDTMASK
                    IF B = 0 OR (t AND ISARRAY) <> 0 OR (t AND ISFLOAT) <> 0 OR (t AND ISSTRING) <> 0 OR (t AND ISOFFSETINBITS) <> 0 THEN a$ = "Only SUB arguments of integer-type allowed": GOTO errmes
                    IF B = 8 THEN ct$ = "int8"
                    IF B = 16 THEN ct$ = "int16"
                    IF B = 32 THEN ct$ = "int32"
                    IF B = 64 THEN ct$ = "int64"
                    IF t AND ISOFFSET THEN ct$ = "ptrszint"
                    IF t AND ISUNSIGNED THEN ct$ = "u" + ct$
                    WriteBufLine TimeTxtBuf, "(" + ct$ + "*)&i64);"

                    e$ = getelements$(ca$, i, n)
                    e$ = fixoperationorder$(e$)
                    IF Error_Happened THEN GOTO errmes
                    l$ = l$ + sp + tlayout$
                    e$ = evaluatetotyp(e$, INTEGER64TYPE - ISPOINTER)
                    IF Error_Happened THEN GOTO errmes
                    WriteBufLine MainTxtBuf, e$ + ");"

                END IF

                WriteBufLine TimeTxtBuf, "break;"
                IF LEN(layout$) = 0 THEN layout$ = l$ ELSE layout$ = layout$ + sp + l$
                layoutdone = 1
                GOTO finishedline
            END IF

        END IF
    END IF




    IF n >= 2 THEN
        IF firstelement$ = "ON" AND secondelement$ = "KEY" THEN
            i = 3
            IF i > n THEN a$ = "Expected (": GOTO errmes
            a2$ = getelement$(ca$, i): i = i + 1
            IF a2$ <> "(" THEN a$ = "Expected (": GOTO errmes
            l$ = SCase$("On" + sp + "Key" + sp2 + "(")
            IF i > n THEN a$ = "Expected ...": GOTO errmes
            B = 0
            x = 0
            e2$ = ""
            FOR i = i TO n
                e$ = getelement$(ca$, i)
                a = ASC(e$)


                IF a = 40 THEN B = B + 1
                IF a = 41 THEN B = B - 1
                IF B = -1 THEN EXIT FOR
                IF LEN(e2$) THEN e2$ = e2$ + sp + e$ ELSE e2$ = e$
            NEXT
            IF i = n + 1 THEN a$ = "Expected )": GOTO errmes
            IF e2$ = "" THEN a$ = "Expected ... )": GOTO errmes

            e$ = fixoperationorder$(e2$)
            IF Error_Happened THEN GOTO errmes
            l$ = l$ + tlayout$ + sp2 + ")" + sp
            e$ = evaluatetotyp(e$, DOUBLETYPE - ISPOINTER)
            IF Error_Happened THEN GOTO errmes
            WriteBufRawData MainTxtBuf, "onkey_setup(" + e$ + ","

            i = i + 1
            IF i > n THEN a$ = "Expected GOSUB/sub-name": GOTO errmes
            a2$ = getelement$(a$, i): i = i + 1
            onkeyid = onkeyid + 1
            WriteBufRawData MainTxtBuf, _TOSTR$(onkeyid) + ","

            IF a2$ = "GOSUB" THEN
                IF i > n THEN a$ = "Expected linenumber/label": GOTO errmes
                a2$ = getelement$(ca$, i): i = i + 1

                WriteBufLine MainTxtBuf, "0);"

                IF validlabel(a2$) = 0 THEN a$ = "Invalid label": GOTO errmes

                v = HashFind(a2$, HASHFLAG_LABEL, ignore, r)
                x = 1
                labchk61:
                IF v THEN
                    s = Labels(r).Scope
                    IF s = 0 OR s = -1 THEN 'main scope?
                        IF s = -1 THEN Labels(r).Scope = 0 'acquire scope
                        x = 0 'already defined
                        tlayout$ = RTRIM$(Labels(r).cn)
                        Labels(r).Scope_Restriction = subfuncn
                        Labels(r).Error_Line = linenumber
                    ELSE
                        IF v = 2 THEN v = HashFindCont(ignore, r): GOTO labchk61
                    END IF
                END IF
                IF x THEN
                    'does not exist
                    nLabels = nLabels + 1: IF nLabels > Labels_Ubound THEN Labels_Ubound = Labels_Ubound * 2: REDIM _PRESERVE Labels(1 TO Labels_Ubound) AS Label_Type
                    Labels(nLabels) = Empty_Label
                    HashAdd a2$, HASHFLAG_LABEL, nLabels
                    r = nLabels
                    Labels(r).State = 0
                    Labels(r).cn = tlayout$
                    Labels(r).Scope = 0
                    Labels(r).Error_Line = linenumber
                    Labels(r).Scope_Restriction = subfuncn
                END IF 'x
                l$ = l$ + SCase$("GoSub") + sp + tlayout$

                WriteBufLine KeyjTxtBuf, "if(key_event_id==" + _TOSTR$(onkeyid) + ")goto LABEL_" + a2$ + ";"

                WriteBufLine KeyTxtBuf, "case " + _TOSTR$(onkeyid) + ":"
                WriteBufLine KeyTxtBuf, "key_event_occurred++;"
                WriteBufLine KeyTxtBuf, "key_event_id=" + _TOSTR$(onkeyid) + ";"
                WriteBufLine KeyTxtBuf, "key_event_occurred++;"
                WriteBufLine KeyTxtBuf, "return_point[next_return_point++]=0;"
                WriteBufLine KeyTxtBuf, "if (next_return_point>=return_points) more_return_points();"
                WriteBufLine KeyTxtBuf, "QBMAIN(NULL);"
                WriteBufLine KeyTxtBuf, "break;"

                IF LEN(layout$) = 0 THEN layout$ = l$ ELSE layout$ = layout$ + sp + l$
                layoutdone = 1
                GOTO finishedline
            ELSE

                'establish whether sub a2$ exists using try
                x = 0
                try = findid(a2$)
                IF Error_Happened THEN GOTO errmes
                DO WHILE try
                    IF id.subfunc = 2 THEN x = 1: EXIT DO
                    IF try = 2 THEN findanotherid = 1: try = findid(a2$) ELSE try = 0
                    IF Error_Happened THEN GOTO errmes
                LOOP
                IF x = 0 THEN a$ = "Expected GOSUB/sub": GOTO errmes

                l$ = l$ + RTRIM$(id.cn)

                WriteBufLine KeyTxtBuf, "case " + _TOSTR$(onkeyid) + ":"
                WriteBufRawData KeyTxtBuf, RTRIM$(id.callname) + "("

                IF id.args > 1 THEN a$ = "SUB requires more than one argument": GOTO errmes

                IF i > n THEN

                    IF id.args = 1 THEN a$ = "Expected argument after SUB": GOTO errmes
                    WriteBufLine MainTxtBuf, "0);"
                    WriteBufLine KeyTxtBuf, ");"

                ELSE

                    IF id.args = 0 THEN a$ = "SUB has no arguments": GOTO errmes

                    t = CVL(id.arg)
                    B = t AND UDTMASK
                    IF B = 0 OR (t AND ISARRAY) <> 0 OR (t AND ISFLOAT) <> 0 OR (t AND ISSTRING) <> 0 OR (t AND ISOFFSETINBITS) <> 0 THEN a$ = "Only SUB arguments of integer-type allowed": GOTO errmes
                    IF B = 8 THEN ct$ = "int8"
                    IF B = 16 THEN ct$ = "int16"
                    IF B = 32 THEN ct$ = "int32"
                    IF B = 64 THEN ct$ = "int64"
                    IF t AND ISOFFSET THEN ct$ = "ptrszint"
                    IF t AND ISUNSIGNED THEN ct$ = "u" + ct$
                    WriteBufLine KeyTxtBuf, "(" + ct$ + "*)&i64);"

                    e$ = getelements$(ca$, i, n)
                    e$ = fixoperationorder$(e$)
                    IF Error_Happened THEN GOTO errmes
                    l$ = l$ + sp + tlayout$
                    e$ = evaluatetotyp(e$, INTEGER64TYPE - ISPOINTER)
                    IF Error_Happened THEN GOTO errmes
                    WriteBufLine MainTxtBuf, e$ + ");"

                END IF

                WriteBufLine KeyTxtBuf, "break;"
                IF LEN(layout$) = 0 THEN layout$ = l$ ELSE layout$ = layout$ + sp + l$
                layoutdone = 1
                GOTO finishedline
            END IF

        END IF
    END IF





    'SHARED (SUB)
    IF n >= 1 THEN
        IF firstelement$ = "SHARED" THEN
            IF n = 1 THEN a$ = "Expected SHARED ...": GOTO errmes
            i = 2
            IF subfuncn = 0 THEN a$ = "SHARED must be used within a SUB/FUNCTION": GOTO errmes



            l$ = SCase$("Shared")
            subfuncshr:

            'get variable name
            n$ = getelement$(ca$, i): i = i + 1

            IF n$ = "" THEN a$ = "Expected SHARED variable-name or SHARED AS type variable-list": GOTO errmes

            IF UCASE$(n$) <> "AS" THEN
                'traditional dim syntax for SHARED
                newSharedSyntax = 0
                s$ = removesymbol(n$)
                IF Error_Happened THEN GOTO errmes
                l2$ = s$ 'either symbol or nothing

                'array?
                a = 0
                IF getelement$(a$, i) = "(" THEN
                    IF getelement$(a$, i + 1) <> ")" THEN a$ = "Expected ()": GOTO errmes
                    i = i + 2
                    a = 1
                    l2$ = l2$ + sp2 + "(" + sp2 + ")"
                END IF

                method = 1

                'specific type?
                t$ = ""
                ts$ = ""
                t3$ = ""
                IF getelement$(a$, i) = "AS" THEN
                    l2$ = l2$ + sp + SCase$("As")
                    getshrtyp:
                    i = i + 1
                    t2$ = getelement$(a$, i)
                    IF t2$ <> "," AND t2$ <> "" THEN
                        IF t$ = "" THEN t$ = t2$ ELSE t$ = t$ + " " + t2$
                        IF t3$ = "" THEN t3$ = t2$ ELSE t3$ = t3$ + sp + t2$
                        GOTO getshrtyp
                    END IF
                    IF t$ = "" THEN a$ = "Expected AS type": GOTO errmes

                    t = typname2typ(t$)
                    IF Error_Happened THEN GOTO errmes
                    IF t AND ISINCONVENTIONALMEMORY THEN t = t - ISINCONVENTIONALMEMORY
                    IF t AND ISPOINTER THEN t = t - ISPOINTER
                    IF t AND ISREFERENCE THEN t = t - ISREFERENCE
                    tsize = typname2typsize
                    method = 0
                    IF (t AND ISUDT) = 0 THEN
                        ts$ = type2symbol$(t$)
                        l2$ = l2$ + sp + SCase2$(t3$)
                    ELSE
                        t3$ = RTRIM$(udtxcname(t AND UDTMASK))
                        l2$ = l2$ + sp + t3$
                    END IF
                    IF Error_Happened THEN GOTO errmes

                END IF 'as

                IF LEN(s$) <> 0 AND LEN(t$) <> 0 THEN a$ = "Expected symbol or AS type after variable name": GOTO errmes

                'no symbol of type specified, apply default
                IF s$ = "" AND t$ = "" THEN
                    IF LEFT$(n$, 1) = "_" THEN v = 27 ELSE v = ASC(UCASE$(n$)) - 64
                    s$ = defineextaz(v)
                END IF

                NormalSharedBlock:
                'switch to main module
                oldsubfunc$ = subfunc$
                subfunc$ = ""
                defdatahandle = GlobTxtBuf
                DataTxtBuf = OpenBuffer%("A", tmpdir$ + "maindata.txt")
                FreeTxtBuf = OpenBuffer%("A", tmpdir$ + "mainfree.txt")

                'use 'try' to locate the variable (if it already exists)
                n2$ = n$ + s$ + ts$ 'note: either ts$ or s$ will exist unless it is a UDT
                try = findid(n2$)
                IF Error_Happened THEN GOTO errmes
                DO WHILE try
                    IF a THEN
                        'an array

                        IF id.arraytype THEN
                            IF LEN(t$) = 0 THEN GOTO shrfound
                            t2 = id.arraytype: t2size = id.tsize
                            IF t2 AND ISINCONVENTIONALMEMORY THEN t2 = t2 - ISINCONVENTIONALMEMORY
                            IF t2 AND ISPOINTER THEN t2 = t2 - ISPOINTER
                            IF t2 AND ISREFERENCE THEN t2 = t2 - ISREFERENCE
                            IF t = t2 AND tsize = t2size THEN GOTO shrfound
                        END IF

                    ELSE
                        'not an array

                        IF id.t THEN
                            IF LEN(t$) = 0 THEN GOTO shrfound
                            t2 = id.t: t2size = id.tsize
                            IF t2 AND ISINCONVENTIONALMEMORY THEN t2 = t2 - ISINCONVENTIONALMEMORY
                            IF t2 AND ISPOINTER THEN t2 = t2 - ISPOINTER
                            IF t2 AND ISREFERENCE THEN t2 = t2 - ISREFERENCE

                            IF Debug THEN PRINT #9, "SHARED:comparing:"; t; t2, tsize; t2size

                            IF t = t2 AND tsize = t2size THEN GOTO shrfound
                        END IF

                    END IF

                    IF try = 2 THEN findanotherid = 1: try = findid(n2$) ELSE try = 0
                    IF Error_Happened THEN GOTO errmes
                LOOP
                'unknown variable
                IF a THEN a$ = "Array '" + n$ + "' not defined": GOTO errmes
                'create variable
                IF LEN(s$) THEN typ$ = s$ ELSE typ$ = t$
                autoIncForceUScore = 1
                IF validname(n$) = 0 THEN a$ = "Invalid variable name": GOTO errmes
                IF GetRCStateVar(OptExpl) THEN a$ = "Variable '" + n$ + "' (" + symbol2fulltypename$(typ$) + ") not defined": GOTO errmes
                retval = dim2(n$, typ$, method, "")
                manageVariableList "", vWatchNewVariable$, 0, 2
                IF Error_Happened THEN GOTO errmes
                'note: variable created!

                shrfound:
                IF newSharedSyntax = 0 THEN
                    l$ = l$ + sp + RTRIM$(id.cn) + l2$
                ELSE
                    IF sharedAsLayoutAdded = 0 THEN
                        sharedAsLayoutAdded = -1
                        l$ = l$ + l2$ + sp$ + RTRIM$(id.cn) + l3$
                    ELSE
                        l$ = l$ + sp$ + RTRIM$(id.cn) + l3$
                    END IF
                END IF

                ids(currentid).share = ids(currentid).share OR 2 'set as temporarily shared

                'method must apply to the current sub/function regardless of how the variable was defined in 'main'
                lmay = LEN(RTRIM$(id.mayhave)): lmust = LEN(RTRIM$(id.musthave))
                IF lmay <> 0 OR lmust <> 0 THEN
                    IF (method = 1 AND lmust = 0) OR (method = 0 AND lmay = 0) THEN
                        revertmaymusthaven = revertmaymusthaven + 1
                        revertmaymusthave(revertmaymusthaven) = currentid
                        SWAP ids(currentid).musthave, ids(currentid).mayhave
                    END IF
                END IF

                'switch back to sub/func
                subfunc$ = oldsubfunc$
                DataTxtBuf = OpenBuffer%("A", tmpdir$ + "data" + _TOSTR$(subfuncn) + ".txt")
                FreeTxtBuf = OpenBuffer%("A", tmpdir$ + "free" + _TOSTR$(subfuncn) + ".txt")
                defdatahandle = DataTxtBuf

                IF newSharedSyntax THEN RETURN

                IF getelement$(a$, i) = "," THEN i = i + 1: l$ = l$ + sp2 + ",": GOTO subfuncshr
                IF getelement$(a$, i) <> "" THEN a$ = "Expected ,": GOTO errmes

                layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                GOTO finishedline
            ELSE
                'new dim syntax for SHARED!
                i = i - 1 'relocate back to "AS"

                'establish the data type:
                t$ = ""
                ts$ = ""
                t3$ = ""
                n$ = ""
                previousElement$ = ""
                l2$ = sp + SCase$("As")
                sharedAsLayoutAdded = 0
                getshrtyp2:
                i = i + 1
                t2$ = getelement$(a$, i)
                IF t2$ <> "," AND t2$ <> "(" AND t2$ <> "" THEN
                    'get first variable name
                    n$ = getelement$(ca$, i)

                    IF LEN(previousElement$) THEN
                        IF t$ = "" THEN t$ = previousElement$ ELSE t$ = t$ + " " + previousElement$
                        IF t3$ = "" THEN t3$ = previousElement$ ELSE t3$ = t3$ + sp + previousElement$
                    END IF
                    previousElement$ = t2$
                    GOTO getshrtyp2
                END IF
                IF t$ = "" THEN a$ = "Expected SHARED AS type variable-list or SHARED variable-name AS type": GOTO errmes

                t = typname2typ(t$)
                IF Error_Happened THEN GOTO errmes
                IF t AND ISINCONVENTIONALMEMORY THEN t = t - ISINCONVENTIONALMEMORY
                IF t AND ISPOINTER THEN t = t - ISPOINTER
                IF t AND ISREFERENCE THEN t = t - ISREFERENCE
                tsize = typname2typsize
                method = 0
                IF (t AND ISUDT) = 0 THEN
                    ts$ = type2symbol$(t$)
                    l2$ = l2$ + sp + SCase2$(t3$)
                ELSE
                    t3$ = RTRIM$(udtxcname(t AND UDTMASK))
                    l2$ = l2$ + sp + t3$
                END IF
                IF Error_Happened THEN GOTO errmes

                subfuncshr2:
                s$ = removesymbol(n$)
                IF Error_Happened THEN GOTO errmes
                IF s$ <> "" THEN
                    a$ = "Cannot use type symbol with SHARED AS type variable-list (" + s$ + ")"
                    GOTO errmes
                END IF

                'array?
                a = 0
                l3$ = ""
                IF getelement$(a$, i) = "(" THEN
                    IF getelement$(a$, i + 1) <> ")" THEN a$ = "Expected ()": GOTO errmes
                    i = i + 2
                    a = 1
                    l3$ = sp2 + "(" + sp2 + ")"
                END IF

                newSharedSyntax = -1
                GOSUB NormalSharedBlock
                newSharedSyntax = 0

                IF getelement$(a$, i) = "," THEN
                    i = i + 1
                    l$ = l$ + sp2 + ","

                    'get next variable name
                    n$ = getelement$(ca$, i): i = i + 1
                    GOTO subfuncshr2
                END IF
                IF getelement$(a$, i) <> "" THEN a$ = "Expected ,": GOTO errmes

                layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                GOTO finishedline
            END IF
        END IF
    END IF

    'EXIT SUB/FUNCTION
    IF n = 2 THEN
        IF firstelement$ = "EXIT" THEN
            sf = 0
            IF secondelement$ = "FUNCTION" THEN sf = 1
            IF secondelement$ = "SUB" THEN sf = 2
            IF sf THEN

                IF LEN(subfunc) = 0 THEN a$ = "EXIT " + secondelement$ + " must be used within a " + secondelement$: GOTO errmes

                WriteBufLine MainTxtBuf, "goto exit_subfunc;"
                IF LEFT$(subfunc, 4) = "SUB_" THEN secondelement$ = SCase$("Sub") ELSE secondelement$ = SCase$("Function")
                l$ = SCase$("Exit") + sp + secondelement$
                layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                GOTO finishedline
            END IF
        END IF
    END IF


    '_ECHO checking
    IF firstelement$ = "_ECHO" THEN
        IF GetRCStateVar(ConsoleOn) = 0 THEN
            a$ = "_ECHO requires $CONSOLE or $CONSOLE:ONLY to be set first": GOTO errmes
        END IF
    END IF


    'ASC statement (fully inline)
    IF n >= 1 THEN
        IF firstelement$ = "ASC" THEN
            IF getelement$(a$, 2) <> "(" THEN a$ = "Expected ( after ASC": GOTO errmes

            'calculate 3 parts
            useposition = 0
            part = 1
            i = 3
            a3$ = ""
            stringvariable$ = ""
            position$ = ""
            B = 0
            DO

                IF i > n THEN 'got part 3
                    IF part <> 3 OR LEN(a3$) = 0 THEN a$ = "Expected ASC ( ... , ... ) = ...": GOTO errmes
                    expression$ = a3$
                    EXIT DO
                END IF

                a2$ = getelement$(ca$, i)
                IF a2$ = "(" THEN B = B + 1
                IF a2$ = ")" THEN B = B - 1

                IF B = -1 THEN

                    IF part = 1 THEN 'eg. ASC(a$)=65
                        IF getelement$(a$, i + 1) <> "=" THEN a$ = "Expected =": GOTO errmes
                        stringvariable$ = a3$
                        position$ = "1"
                        part = 3: a3$ = "": i = i + 1: GOTO ascgotpart
                    END IF

                    IF part = 2 THEN 'eg. ASC(a$,i)=65
                        IF getelement$(a$, i + 1) <> "=" THEN a$ = "Expected =": GOTO errmes
                        useposition = 1
                        position$ = a3$
                        part = 3: a3$ = "": i = i + 1: GOTO ascgotpart
                    END IF

                    'fall through, already in part 3

                END IF

                IF a2$ = "," AND B = 0 THEN
                    IF part = 1 THEN stringvariable$ = a3$: part = 2: a3$ = "": GOTO ascgotpart
                END IF

                IF LEN(a3$) THEN a3$ = a3$ + sp + a2$ ELSE a3$ = a2$
                ascgotpart:
                i = i + 1
            LOOP
            IF LEN(stringvariable$) = 0 OR LEN(position$) = 0 THEN a$ = "Expected ASC ( ... , ... ) = ...": GOTO errmes

            'validate stringvariable$
            stringvariable$ = fixoperationorder$(stringvariable$)
            IF Error_Happened THEN GOTO errmes
            l$ = SCase$("Asc") + sp2 + "(" + sp2 + tlayout$

            e$ = evaluate(stringvariable$, sourcetyp)
            IF Error_Happened THEN GOTO errmes
            IF (sourcetyp AND ISREFERENCE) = 0 OR (sourcetyp AND ISSTRING) = 0 THEN a$ = "Expected ASC ( string-variable , ...": GOTO errmes
            stringvariable$ = evaluatetotyp(stringvariable$, ISSTRING)
            IF Error_Happened THEN GOTO errmes



            IF position$ = "1" THEN
                IF useposition THEN l$ = l$ + sp2 + "," + sp + "1" + sp2 + ")" + sp + "=" ELSE l$ = l$ + sp2 + ")" + sp + "="

                WriteBufLine MainTxtBuf, "tqbs=" + stringvariable$ + "; if (!is_error_pending()){"
                e$ = fixoperationorder$(expression$)
                IF Error_Happened THEN GOTO errmes
                l$ = l$ + sp + tlayout$
                e$ = evaluatetotyp(e$, 32&)
                IF Error_Happened THEN GOTO errmes
                WriteBufLine MainTxtBuf, "tmp_long=" + e$ + "; if (!is_error_pending()){"
                WriteBufLine MainTxtBuf, "if (tqbs->len){tqbs->chr[0]=tmp_long;}else{error(5);}"
                WriteBufLine MainTxtBuf, "}}"

            ELSE

                WriteBufLine MainTxtBuf, "tqbs=" + stringvariable$ + "; if (!is_error_pending()){"
                e$ = fixoperationorder$(position$)
                IF Error_Happened THEN GOTO errmes
                l$ = l$ + sp2 + "," + sp + tlayout$ + sp2 + ")" + sp + "="
                e$ = evaluatetotyp(e$, 32&)
                IF Error_Happened THEN GOTO errmes
                WriteBufLine MainTxtBuf, "tmp_fileno=" + e$ + "; if (!is_error_pending()){"
                e$ = fixoperationorder$(expression$)
                IF Error_Happened THEN GOTO errmes
                l$ = l$ + sp + tlayout$
                e$ = evaluatetotyp(e$, 32&)
                IF Error_Happened THEN GOTO errmes
                WriteBufLine MainTxtBuf, "tmp_long=" + e$ + "; if (!is_error_pending()){"
                WriteBufLine MainTxtBuf, "if ((tmp_fileno>0)&&(tmp_fileno<=tqbs->len)){tqbs->chr[tmp_fileno-1]=tmp_long;}else{error(5);}"
                WriteBufLine MainTxtBuf, "}}}"

            END IF
            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
            GOTO finishedline
        END IF
    END IF




    'MID$ statement
    IF n >= 1 THEN
        IF firstelement$ = "MID$" THEN
            IF getelement$(a$, 2) <> "(" THEN a$ = "Expected ( after MID$": GOTO errmes
            'calculate 4 parts
            length$ = ""
            part = 1
            i = 3
            a3$ = ""
            stringvariable$ = ""
            start$ = ""
            B = 0
            DO
                IF i > n THEN
                    IF part <> 4 OR a3$ = "" THEN a$ = "Expected MID$(...)=...": GOTO errmes
                    stringexpression$ = a3$
                    EXIT DO
                END IF
                a2$ = getelement$(ca$, i)
                IF a2$ = "(" THEN B = B + 1
                IF a2$ = ")" THEN B = B - 1
                IF B = -1 THEN
                    IF part = 2 THEN
                        IF getelement$(a$, i + 1) <> "=" THEN a$ = "Expected = after )": GOTO errmes
                        start$ = a3$: part = 4: a3$ = "": i = i + 1: GOTO midgotpart
                    END IF
                    IF part = 3 THEN
                        IF getelement$(a$, i + 1) <> "=" THEN a$ = "Expected = after )": GOTO errmes
                        IF a3$ = "" THEN a$ = "Omit , before ) if omitting length in MID$ statement": GOTO errmes
                        length$ = a3$: part = 4: a3$ = "": i = i + 1: GOTO midgotpart
                    END IF
                END IF
                IF a2$ = "," AND B = 0 THEN
                    IF part = 1 THEN stringvariable$ = a3$: part = 2: a3$ = "": GOTO midgotpart
                    IF part = 2 THEN start$ = a3$: part = 3: a3$ = "": GOTO midgotpart
                END IF
                IF LEN(a3$) THEN a3$ = a3$ + sp + a2$ ELSE a3$ = a2$
                midgotpart:
                i = i + 1
            LOOP
            IF stringvariable$ = "" THEN a$ = "Syntax error - first parameter must be a string variable/array-element": GOTO errmes
            IF start$ = "" THEN a$ = "Syntax error - second parameter not optional": GOTO errmes
            'check if it is a valid source string
            stringvariable$ = fixoperationorder$(stringvariable$)
            IF Error_Happened THEN GOTO errmes
            l$ = SCase$("Mid$") + sp2 + "(" + sp2 + tlayout$
            e$ = evaluate(stringvariable$, sourcetyp)
            IF Error_Happened THEN GOTO errmes
            IF (sourcetyp AND ISREFERENCE) = 0 OR (sourcetyp AND ISSTRING) = 0 THEN a$ = "MID$ expects a string variable/array-element as its first argument": GOTO errmes
            stringvariable$ = evaluatetotyp(stringvariable$, ISSTRING)
            IF Error_Happened THEN GOTO errmes

            start$ = fixoperationorder$(start$)
            IF Error_Happened THEN GOTO errmes
            l$ = l$ + sp2 + "," + sp + tlayout$
            start$ = evaluatetotyp((start$), 32&)

            stringexpression$ = fixoperationorder$(stringexpression$)
            IF Error_Happened THEN GOTO errmes
            l2$ = tlayout$
            stringexpression$ = evaluatetotyp(stringexpression$, ISSTRING)
            IF Error_Happened THEN GOTO errmes

            IF LEN(length$) THEN
                length$ = fixoperationorder$(length$)
                IF Error_Happened THEN GOTO errmes
                l$ = l$ + sp2 + "," + sp + tlayout$
                length$ = evaluatetotyp(length$, 32&)
                IF Error_Happened THEN GOTO errmes
                WriteBufLine MainTxtBuf, "sub_mid(" + stringvariable$ + "," + start$ + "," + length$ + "," + stringexpression$ + ",1);"
            ELSE
                WriteBufLine MainTxtBuf, "sub_mid(" + stringvariable$ + "," + start$ + ",0," + stringexpression$ + ",0);"
            END IF

            l$ = l$ + sp2 + ")" + sp + "=" + sp + l2$
            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
            GOTO finishedline
        END IF
    END IF


    IF n >= 2 THEN
        IF firstelement$ = "ERASE" THEN
            i = 2
            l$ = SCase$("Erase")
            erasenextarray:
            ' Parse one ERASE target as a full expression rather than a single token.
            ' This is required for forms such as ERASE P(0).MemberArray, where the target is a
            ' TYPE member array rather than a classic top-level QB64 array. Later code resolves
            ' whether that member is inline (unmarked/_Static) or descriptor-backed (_Dynamic).
            targetfirst = i
            B = 0
            DO WHILE i <= n
                targettoken$ = getelement$(ca$, i)
                IF targettoken$ = "(" THEN B = B + 1
                IF targettoken$ = ")" THEN B = B - 1
                IF B < 0 THEN a$ = "Expected (": GOTO errmes
                IF B = 0 AND targettoken$ = "," THEN EXIT DO
                i = i + 1
            LOOP
            IF B <> 0 THEN a$ = "Expected )": GOTO errmes
            targetlast = i - 1
            IF targetlast < targetfirst THEN a$ = "Expected array-name": GOTO errmes
            var$ = getelements$(ca$, targetfirst, targetlast)

            ' Reject ERASE () before member-expression evaluation. The member-array parser
            ' accepts full expressions, but an empty parenthesized target must report
            ' the standard undefined-array diagnostic.
            IF IsEmptyParenthesizedTarget%(var$) THEN a$ = "Undefined array passed to ERASE": GOTO errmes
            IF HasIndexedFinalMemberArray%(var$) THEN a$ = "Incorrect number of arguments": GOTO errmes

            x$ = var$: ls$ = removesymbol(x$)
            IF Error_Happened THEN Error_Happened = 0

            IF FindArray(var$) THEN
                IF Error_Happened THEN GOTO errmes
                l$ = l$ + sp + RTRIM$(id.cn) + ls$
                'erase the array
                clearerase:
                n$ = RTRIM$(id.callname)
                bytesperelement$ = _TOSTR$((id.arraytype AND UDTMASK) \ 8)
                udt = 0
                IF id.arraytype AND ISSTRING THEN bytesperelement$ = _TOSTR$(id.tsize)
                IF id.arraytype AND ISOFFSETINBITS THEN bytesperelement$ = _TOSTR$((id.arraytype AND UDTMASK)) + "/8+1"
                IF id.arraytype AND ISUDT THEN
                    udt = id.arraytype AND UDTMASK
                    IF id.dynudt THEN
                        bytesperelement$ = _TOSTR$(UDTDynLayoutSize&(udt) \ 8)
                    ELSE
                        bytesperelement$ = _TOSTR$(udtxsize(udt) \ 8)
                    END IF
                END IF
                WriteBufLine MainTxtBuf, "if (" + n$ + "[2]&1){" 'array is defined
                WriteBufLine MainTxtBuf, "if (" + n$ + "[2]&2){" 'array is static
                IF udt > 0 AND id.dynudt AND UDTDynHasMemberArrays%(udt, id.dynudtmode) THEN
                    ' A DIM/static-storage parent array may contain explicit _Dynamic TYPE member arrays.
                    ' ERASE must release those nested descriptors before clearing the parent
                    ' storage, otherwise descriptor allocations and _MEM locks would leak.
                    WriteBufRawData MainTxtBuf, "tmp_long="
                    FOR i2 = 1 TO ABS(id.arrayelements)
                        IF i2 <> 1 THEN WriteBufRawData MainTxtBuf, "*"
                        WriteBufRawData MainTxtBuf, n$ + "[" + _TOSTR$(i2 * 4 - 4 + 5) + "]"
                    NEXT
                    WriteBufLine MainTxtBuf, ";"
                    WriteBufLine MainTxtBuf, "while(tmp_long--){"
                    acc$ = ""
                    AppendDynUDTDescFree n$ + "[0]", udt, 0, bytesperelement$, acc$, id.dynudtmode
                    IF Error_Happened THEN GOTO errmes
                    WriteBufLine MainTxtBuf, acc$
                    WriteBufLine MainTxtBuf, "}"
                END IF
                IF (id.arraytype AND ISSTRING) <> 0 AND (id.arraytype AND ISFIXEDLENGTH) = 0 THEN
                    WriteBufRawData MainTxtBuf, "tmp_long="
                    FOR i2 = 1 TO ABS(id.arrayelements)
                        IF i2 <> 1 THEN WriteBufRawData MainTxtBuf, "*"
                        WriteBufRawData MainTxtBuf, n$ + "[" + _TOSTR$(i2 * 4 - 4 + 5) + "]"
                    NEXT
                    WriteBufLine MainTxtBuf, ";"
                    WriteBufLine MainTxtBuf, "while(tmp_long--){"
                    WriteBufLine MainTxtBuf, "((qbs*)(((uint64*)(" + n$ + "[0]))[tmp_long]))->len=0;"
                    WriteBufLine MainTxtBuf, "}"
                ELSEIF udt > 0 AND udtxvariable(udt) AND NOT (id.dynudt AND UDTDynHasMemberArrays%(udt, id.dynudtmode)) THEN
                    ' Static arrays of UDTs must clear nested variable members element-by-element.
                    WriteBufRawData MainTxtBuf, "tmp_long="
                    FOR i2 = 1 TO ABS(id.arrayelements)
                        IF i2 <> 1 THEN WriteBufRawData MainTxtBuf, "*"
                        WriteBufRawData MainTxtBuf, n$ + "[" + _TOSTR$(i2 * 4 - 4 + 5) + "]"
                    NEXT
                    WriteBufLine MainTxtBuf, ";"
                    WriteBufLine MainTxtBuf, "while(tmp_long--){"
                    acc$ = ""
                    clear_array_udt_varstrings n$, udt, 0, bytesperelement$, acc$
                    WriteBufLine MainTxtBuf, acc$
                    WriteBufLine MainTxtBuf, "}"
                ELSE
                    'numeric / fixed-length / plain UDT
                    'clear array
                    WriteBufRawData MainTxtBuf, "memset((void*)(" + n$ + "[0]),0,"
                    FOR i2 = 1 TO ABS(id.arrayelements)
                        IF i2 <> 1 THEN WriteBufRawData MainTxtBuf, "*"
                        WriteBufRawData MainTxtBuf, n$ + "[" + _TOSTR$(i2 * 4 - 4 + 5) + "]"
                    NEXT
                    WriteBufLine MainTxtBuf, "*" + bytesperelement$ + ");"
                END IF
                WriteBufLine MainTxtBuf, "}else{" 'array is dynamic
                '1. free memory & any allocated strings
                IF (id.arraytype AND ISSTRING) <> 0 AND (id.arraytype AND ISFIXEDLENGTH) = 0 THEN
                    'free strings
                    WriteBufRawData MainTxtBuf, "tmp_long="
                    FOR i2 = 1 TO ABS(id.arrayelements)
                        IF i2 <> 1 THEN WriteBufRawData MainTxtBuf, "*"
                        WriteBufRawData MainTxtBuf, n$ + "[" + _TOSTR$(i2 * 4 - 4 + 5) + "]"
                    NEXT
                    WriteBufLine MainTxtBuf, ";"
                    WriteBufLine MainTxtBuf, "while(tmp_long--){"
                    WriteBufLine MainTxtBuf, "qbs_free((qbs*)(((uint64*)(" + n$ + "[0]))[tmp_long]));"
                    WriteBufLine MainTxtBuf, "}"
                    'free memory
                    WriteBufLine MainTxtBuf, "free((void*)(" + n$ + "[0]));"
                ELSE
                    IF udt > 0 AND udtxvariable(udt) AND NOT (id.dynudt AND UDTDynHasMemberArrays%(udt, id.dynudtmode)) THEN
                        ' Dynamic arrays of UDTs must free nested variable members before the raw block is freed.
                        WriteBufRawData MainTxtBuf, "tmp_long="
                        FOR i2 = 1 TO ABS(id.arrayelements)
                            IF i2 <> 1 THEN WriteBufRawData MainTxtBuf, "*"
                            WriteBufRawData MainTxtBuf, n$ + "[" + _TOSTR$(i2 * 4 - 4 + 5) + "]"
                        NEXT
                        WriteBufLine MainTxtBuf, ";"
                        WriteBufLine MainTxtBuf, "while(tmp_long--){"
                        acc$ = ""
                        free_array_udt_varstrings n$, udt, 0, bytesperelement$, acc$
                        WriteBufLine MainTxtBuf, acc$
                        WriteBufLine MainTxtBuf, "}"
                    END IF
                    IF udt > 0 AND id.dynudt AND UDTDynHasMemberArrays%(udt, id.dynudtmode) THEN
                        WriteBufLine MainTxtBuf, "if (" + n$ + "[2]&8){"
                        WriteBufRawData MainTxtBuf, "tmp_long="
                        FOR i2 = 1 TO ABS(id.arrayelements)
                            IF i2 <> 1 THEN WriteBufRawData MainTxtBuf, "*"
                            WriteBufRawData MainTxtBuf, n$ + "[" + _TOSTR$(i2 * 4 - 4 + 5) + "]"
                        NEXT
                        WriteBufLine MainTxtBuf, ";"
                        WriteBufLine MainTxtBuf, "while(tmp_long--){"
                        acc$ = ""
                        AppendDynUDTDescFree n$ + "[0]", udt, 0, bytesperelement$, acc$, id.dynudtmode
                        IF Error_Happened THEN GOTO errmes
                        WriteBufLine MainTxtBuf, acc$
                        WriteBufLine MainTxtBuf, "}"
                        WriteBufLine MainTxtBuf, "}"
                    END IF
                    'free memory
                    WriteBufLine MainTxtBuf, "if (" + n$ + "[2]&4){" 'cmem array
                    WriteBufLine MainTxtBuf, "cmem_dynamic_free((uint8*)(" + n$ + "[0]));"
                    WriteBufLine MainTxtBuf, "}else{" 'non-cmem array
                    WriteBufLine MainTxtBuf, "free((void*)(" + n$ + "[0]));"
                    WriteBufLine MainTxtBuf, "}"
                END IF
                '2. set array (and its elements) as undefined
                WriteBufLine MainTxtBuf, n$ + "[2]^=1;" 'remove defined flag, keeping other flags (such as cmem)
                'set dimensions as undefined
                FOR i2 = 1 TO ABS(id.arrayelements)
                    B = i2 * 4
                    WriteBufLine MainTxtBuf, n$ + "[" + _TOSTR$(B) + "]=2147483647;" 'base
                    WriteBufLine MainTxtBuf, n$ + "[" + _TOSTR$(B + 1) + "]=0;" 'num. index
                    WriteBufLine MainTxtBuf, n$ + "[" + _TOSTR$(B + 2) + "]=0;" 'multiplier
                NEXT
                IF (id.arraytype AND ISSTRING) <> 0 AND (id.arraytype AND ISFIXEDLENGTH) = 0 THEN
                    WriteBufLine MainTxtBuf, n$ + "[0]=(ptrszint)&nothingstring;"
                ELSE
                    WriteBufLine MainTxtBuf, n$ + "[0]=(ptrszint)nothingvalue;"
                END IF
                WriteBufLine MainTxtBuf, "}" 'static/dynamic
                WriteBufLine MainTxtBuf, "}" 'array is defined
                IF clearerasereturn = 1 THEN clearerasereturn = 0: GOTO clearerasereturned
                GOTO erasedarray
            END IF
            IF Error_Happened THEN GOTO errmes

            ' If FindArray() did not match, try a bare inline TYPE member-array target.
            ' Only the nested inline block is cleared; the parent TYPE value remains intact.
            udt_allow_bare_array = -1
            targetref$ = evaluate(var$, targettyp)
            udt_allow_bare_array = 0
            IF Error_Happened = 0 THEN
                IF (targettyp AND ISREFERENCE) <> 0 AND (targettyp AND ISARRAY) <> 0 THEN
                    s1 = INSTR(targetref$, sp3)
                    IF s1 THEN s2 = INSTR(s1 + LEN(sp3), targetref$, sp3) ELSE s2 = 0
                    IF s2 THEN s3 = INSTR(s2 + LEN(sp3), targetref$, sp3) ELSE s3 = 0
                    IF s3 THEN
                        idnum = VAL(LEFT$(targetref$, s1 - 1))
                        member_element_id = VAL(MID$(targetref$, s2 + LEN(sp3), s3 - (s2 + LEN(sp3)))) 'TYPE member-array metadata index
                        offset$ = MID$(targetref$, s3 + LEN(sp3))
                        getid idnum
                        IF Error_Happened THEN GOTO errmes
                        base$ = "UDT_" + RTRIM$(id.n)
                        IF id.t = 0 THEN base$ = "ARRAY_" + base$ + "[0]"
                        base$ = scope$ + base$
                        ptr$ = "((char*)" + base$ + "+(" + offset$ + "))"
                        l$ = l$ + sp + CompactMemberRefLayout$(var$)

                        IF id.dynudt AND UDTMemberDynDesc%(member_element_id) THEN
                            acc$ = ""
                            AppendDynMemberLockBump ptr$, acc$
                            AppendDynMemberEraseTyped ptr$, udt_dyn_array_elem_bytes(member_element_id), 0, DynMemVarStr%(member_element_id), acc$, id.dynudtmode
                            IF Error_Happened THEN GOTO errmes
                            WriteBufLine MainTxtBuf, acc$
                            GOTO erasedarray
                        END IF

                        memberbytes = udtesize(member_element_id) \ 8
                        memberelems = udtearrayelements(member_element_id)
                        IF memberelems <= 0 THEN a$ = "Expected array-name": GOTO errmes
                        elementbytes = memberbytes \ memberelems

                        IF (udtetype(member_element_id) AND ISSTRING) <> 0 AND (udtetype(member_element_id) AND ISFIXEDLENGTH) = 0 THEN
                            FOR i2 = 0 TO memberelems - 1
                                WriteBufLine MainTxtBuf, "(*(qbs**)(" + ptr$ + "+" + _TOSTR$(i2 * elementbytes) + "))->len=0;"
                            NEXT
                        ELSEIF (udtetype(member_element_id) AND ISSTRING) <> 0 AND (udtetype(member_element_id) AND ISFIXEDLENGTH) <> 0 THEN
                            ' Match ordinary QB64PE static-array reset semantics for STRING * N.
                            ' Fixed-length string storage is cleared to NUL bytes here, not spaces.
                            WriteBufLine MainTxtBuf, "memset((void*)" + ptr$ + ",0," + _TOSTR$(memberbytes) + ");"
                        ELSEIF (udtetype(member_element_id) AND ISUDT) <> 0 AND udtxvariable(udtetype(member_element_id) AND UDTMASK) THEN
                            FOR i2 = 0 TO memberelems - 1
                                clear_udt_with_varstrings ptr$, udtetype(member_element_id) AND UDTMASK, MainTxtBuf, i2 * elementbytes
                            NEXT
                        ELSE
                            WriteBufLine MainTxtBuf, "memset((void*)" + ptr$ + ",0," + _TOSTR$(memberbytes) + ");"
                        END IF
                        GOTO erasedarray
                    END IF
                END IF
            ELSE
                Error_Happened = 0
            END IF
            a$ = "Undefined array passed to ERASE": GOTO errmes

            erasedarray:
            IF i <= n THEN
                n$ = getelement$(a$, i)
                IF n$ <> "," THEN a$ = "Expected ,": GOTO errmes
                l$ = l$ + sp2 + ","
                i = i + 1: IF i > n THEN a$ = "Expected , ...": GOTO errmes
                GOTO erasenextarray
            END IF

            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
            GOTO finishedline
        END IF
    END IF


    'DIM/REDIM/STATIC
    IF n >= 2 THEN
        dimoption = 0: redimoption = 0: commonoption = 0
        IF firstelement$ = "DIM" THEN l$ = SCase$("Dim"): dimoption = 1
        IF firstelement$ = "REDIM" THEN
            l$ = SCase$("ReDim")
            dimoption = 2: redimoption = 1
            IF secondelement$ = "_PRESERVE" THEN
                redimoption = 2
                l$ = l$ + sp + SCase$("_Preserve")
                IF n = 2 THEN a$ = "Expected REDIM _PRESERVE ...": GOTO errmes
            END IF
            IF secondelement$ = "_RETAIN" THEN
                redimoption = 3
                l$ = l$ + sp + SCase$("_Retain")
                IF n = 2 THEN a$ = "Expected REDIM _RETAIN ...": GOTO errmes
            END IF
        END IF
        IF firstelement$ = "STATIC" THEN l$ = SCase$("Static"): dimoption = 3
        IF firstelement$ = "COMMON" THEN l$ = SCase$("Common"): dimoption = 1: commonoption = 1
        IF dimoption THEN

            IF dimoption = 3 AND subfuncn = 0 THEN a$ = "STATIC must be used within a SUB/FUNCTION": GOTO errmes
            IF commonoption = 1 AND subfuncn <> 0 THEN a$ = "COMMON cannot be used within a SUB/FUNCTION": GOTO errmes

            i = 2
            IF redimoption >= 2 THEN i = 3

            IF dimoption <> 3 THEN 'shared cannot be static
                a2$ = getelement(a$, i)
                IF a2$ = "SHARED" THEN
                    IF subfuncn <> 0 THEN a$ = "DIM/REDIM SHARED invalid within a SUB/FUNCTION": GOTO errmes
                    dimshared = 1
                    i = i + 1
                    l$ = l$ + sp + SCase$("Shared")
                END IF
            END IF

            IF dimoption = 3 THEN dimstatic = 1: AllowLocalName = 1

            'look for new dim syntax: DIM AS variabletype var1, var2, etc....
            e$ = getelement$(a$, i)
            IF e$ <> "AS" THEN
                'no "AS", so this is the traditional dim syntax
                dimnext:
                newDimSyntax = 0
                notype = 0
                listarray = 0


                'old chain code
                'chaincommonarray=0

                ' REDIM uses a dedicated parser path for inline TYPE member arrays such as:
                '   REDIM Item.Values(0 TO 3)
                '   REDIM Items(0).Values(0 TO 3)
                ' The ordinary-array parser remains unchanged and this path is selected only
                ' when the REDIM target contains a member dereference.
                redimMemberHandled = 0
                redimTargetComma = 0
                IF redimoption THEN
                    redimTargetFirst = i
                    B = 0
                    DO WHILE i <= n
                        redimTok$ = getelement$(ca$, i)
                        IF redimTok$ = "(" THEN B = B + 1
                        IF redimTok$ = ")" THEN B = B - 1
                        IF B = 0 AND redimTok$ = "," THEN EXIT DO
                        i = i + 1
                    LOOP
                    redimTargetComma = i
                    redimTargetLast = i - 1
                    IF redimTargetLast >= redimTargetFirst THEN
                        redimFullTarget$ = getelements$(ca$, redimTargetFirst, redimTargetLast)

                        '------
                        redimLastOpen = 0
                        redimLastClose = 0
                        redimDepth = 0
                        redimOpenCandidate = 0
                        redimTargetExpr$ = ""
                        redimBounds$ = ""

                        FOR redimScan = redimTargetFirst TO redimTargetLast
                            redimTok$ = getelement$(ca$, redimScan)
                            IF redimTok$ = "(" THEN
                                IF redimDepth = 0 THEN redimOpenCandidate = redimScan
                                redimDepth = redimDepth + 1
                            ELSEIF redimTok$ = ")" THEN
                                redimDepth = redimDepth - 1
                                IF redimDepth < 0 THEN a$ = "Expected )": GOTO errmes
                                IF redimDepth = 0 THEN
                                    redimLastOpen = redimOpenCandidate
                                    redimLastClose = redimScan
                                END IF
                            END IF
                        NEXT
                        IF redimDepth <> 0 THEN a$ = "Expected )": GOTO errmes

                        IF redimLastOpen <> 0 AND redimLastClose <> 0 THEN
                            redimMemberDeclOK = 0
                            redimTypeSuffix$ = ""

                            IF redimLastClose = redimTargetLast THEN
                                redimMemberDeclOK = -1
                            ELSEIF redimLastClose < redimTargetLast THEN
                                IF UCASE$(getelement$(ca$, redimLastClose + 1)) = "AS" THEN
                                    redimMemberDeclOK = -1
                                    ' Use the normalized statement text for AS type parsing. ca$ preserves user casing,
                                    ' but typname2typ() does not accept lower-case builtin names here, so forms such as
                                    ' REDIM _RETAIN parent(i).member(n) AS LONG were reported as "Undefined type".
                                    redimTypeSuffix$ = getelements$(a$, redimLastClose + 1, redimTargetLast)
                                END IF
                            END IF

                            IF redimMemberDeclOK THEN
                                redimTargetExpr$ = getelements$(ca$, redimTargetFirst, redimLastOpen - 1)
                                redimBounds$ = getelements$(ca$, redimLastOpen + 1, redimLastClose - 1)
                            END IF
                        END IF

                        IF redimTargetExpr$ <> "" AND redimBounds$ <> "" AND INSTR(redimTargetExpr$, ".") THEN 'member-array target confirmed by a dotted parent expression
                            '-----

                            ' Evaluate the target as a whole bare member-array reference.
                            udt_allow_bare_array = -1
                            redimTargetRef$ = evaluate(redimTargetExpr$, redimTargetTyp)
                            udt_allow_bare_array = 0
                            IF Error_Happened THEN GOTO errmes
                            IF (redimTargetTyp AND ISREFERENCE) = 0 OR (redimTargetTyp AND ISARRAY) = 0 THEN
                                a$ = "Expected array-name": GOTO errmes
                            END IF

                            redimS1 = INSTR(redimTargetRef$, sp3)
                            IF redimS1 THEN redimS2 = INSTR(redimS1 + LEN(sp3), redimTargetRef$, sp3) ELSE redimS2 = 0
                            IF redimS2 THEN redimS3 = INSTR(redimS2 + LEN(sp3), redimTargetRef$, sp3) ELSE redimS3 = 0
                            IF redimS3 = 0 THEN a$ = "Expected array-name": GOTO errmes

                            redimIdNum = VAL(LEFT$(redimTargetRef$, redimS1 - 1))
                            redimE = VAL(MID$(redimTargetRef$, redimS2 + LEN(sp3), redimS3 - (redimS2 + LEN(sp3))))
                            redimOffset$ = MID$(redimTargetRef$, redimS3 + LEN(sp3))

                            getid redimIdNum
                            IF Error_Happened THEN GOTO errmes

                            redimBase$ = "UDT_" + RTRIM$(id.n)
                            IF id.t = 0 THEN redimBase$ = "ARRAY_" + redimBase$ + "[0]"
                            redimBase$ = scope$ + redimBase$

                            IF redimTypeSuffix$ <> "" THEN
                                IF numelements(redimTypeSuffix$) < 2 OR UCASE$(getelement$(redimTypeSuffix$, 1)) <> "AS" THEN a$ = "Expected AS type": GOTO errmes
                                redimTypeName$ = UCASE$(getelements$(redimTypeSuffix$, 2, numelements(redimTypeSuffix$)))
                                IF redimTypeName$ = "" THEN a$ = "Expected AS type": GOTO errmes
                                redimTypeValue = typname2typ(redimTypeName$)
                                IF Error_Happened THEN GOTO errmes
                                IF redimTypeValue = 0 THEN a$ = "Undefined type": GOTO errmes
                                redimTypeSize = typname2typsize
                                redimTypeMask = redimTypeValue AND (ISFLOAT + ISUDT + UDTMASK + ISUNSIGNED + ISSTRING + ISFIXEDLENGTH + ISOFFSETINBITS)
                                redimMemberMask = udtetype(redimE) AND (ISFLOAT + ISUDT + UDTMASK + ISUNSIGNED + ISSTRING + ISFIXEDLENGTH + ISOFFSETINBITS)
                                IF redimTypeMask <> redimMemberMask OR redimTypeSize <> udtetypesize(redimE) THEN
                                    a$ = "REDIM type does not match the declared TYPE member array": GOTO errmes
                                END IF
                            ELSE
                                'Without AS, a compact member REDIM such as parent(i).member(n)
                                'has the same implicit-type ambiguity as the old REDIM syntax.
                                'Do not silently reinterpret it as the already-known member type.
                                'Keep the unambiguous lower TO upper form working, and also allow
                                'an explicit type symbol on the member name because udtreference$
                                'has already verified that symbol against the actual member type.
                                redimCheckName$ = getelement$(ca$, redimLastOpen - 1)
                                redimCheckSym$ = removesymbol$(redimCheckName$)
                                IF Error_Happened THEN GOTO errmes
                                IF redimCheckSym$ = "" THEN
                                    IF BoundsHaveTopTo%(redimBounds$) = 0 THEN
                                        a$ = "REDIM of a TYPE member array must include AS <type> or explicit lower TO upper bounds": GOTO errmes
                                    END IF
                                END IF
                            END IF

                            ' Compact member dereferences inside bounds without changing expression order.

                            redimLayoutBounds$ = CompactMemberRefLayout$(redimBounds$)
                            l$ = l$ + sp + CompactMemberRefLayout$(redimTargetExpr$) + "(" + sp2 + redimLayoutBounds$ + ")"

                            IF redimTypeSuffix$ <> "" THEN l$ = l$ + sp + redimTypeSuffix$

                            IF id.dynudt AND UDTMemberDynDesc%(redimE) THEN
                                ' REDIM of a descriptor-backed TYPE member array changes only that
                                ' member descriptor for the selected parent element. It must not touch
                                ' sibling inline members or the parent UDT storage.
                                redimMemberElems = udtearrayelements(redimE)
                                redimElementBytes = udt_dyn_array_elem_bytes(redimE)
                                redimElemUDT = 0
                                IF (udtetype(redimE) AND ISUDT) <> 0 THEN redimElemUDT = udtetype(redimE) AND UDTMASK
                                redimSlot$ = "((char*)" + redimBase$ + "+(" + redimOffset$ + "))"
                                redimAcc$ = ""
                                redimDynPrefix$ = "dyn_mem_rt_" + _TOSTR$(uniquenumber)
                                BuildDynMemberBoundsPrep redimBounds$, redimDynPrefix$, redimDynDims, redimAcc$
                                IF Error_Happened THEN GOTO errmes
                                AppendDynMemberRedim redimDynPrefix$, redimDynDims, redimSlot$, redimElementBytes, redimElemUDT, DynMemVarStr%(redimE), redimoption, redimAcc$, id.dynudtmode
                                IF Error_Happened THEN GOTO errmes
                                WriteBufLine MainTxtBuf, redimAcc$
                            ELSE
                                ' The requested bounds must describe the exact same inline storage layout.
                                ' An inline TYPE member array (unmarked or _Static) has fixed bounds, so REDIM may only
                                ' reinitialize it when the bounds match exactly.
                                IF ParseUDTArrayBounds(redimBounds$, redimLowerBound, redimElementCount, redimDimCount, redimDesc$) = 0 THEN GOTO errmes
                                IF redimDimCount <> udtearraydims(redimE) OR redimDesc$ <> udtearraydesc(redimE) THEN
                                    a$ = "Cannot change the number of elements an array has!": GOTO errmes
                                END IF

                                ' Build a pointer to the first byte of the inline member-array storage.
                                redimPtr$ = "((char*)" + redimBase$ + "+(" + redimOffset$ + "))"

                                IF redimoption = 1 THEN
                                    redimMemberBytes = udtesize(redimE) \ 8
                                    redimMemberElems = udtearrayelements(redimE)
                                    redimElementBytes = redimMemberBytes \ redimMemberElems

                                    ' Inline TYPE member arrays (unmarked or _Static) have compile-time fixed storage.
                                    ' Plain REDIM on a matching descriptor reinitializes that inline storage.
                                    ' REDIM _PRESERVE/_RETAIN on the same descriptor must leave the bytes untouched.
                                    IF (udtetype(redimE) AND ISSTRING) <> 0 AND (udtetype(redimE) AND ISFIXEDLENGTH) = 0 THEN
                                        FOR redimI2 = 0 TO redimMemberElems - 1
                                            WriteBufLine MainTxtBuf, "(*(qbs**)(" + redimPtr$ + "+" + _TOSTR$(redimI2 * redimElementBytes) + "))->len=0;"
                                        NEXT
                                    ELSEIF (udtetype(redimE) AND ISSTRING) <> 0 AND (udtetype(redimE) AND ISFIXEDLENGTH) <> 0 THEN
                                        ' Match ordinary QB64PE static-array REDIM semantics for STRING * N.
                                        ' Fixed-length string storage is reinitialized to NUL bytes, not spaces.
                                        WriteBufLine MainTxtBuf, "memset((void*)" + redimPtr$ + ",0," + _TOSTR$(redimMemberBytes) + ");"
                                    ELSEIF (udtetype(redimE) AND ISUDT) <> 0 AND udtxvariable(udtetype(redimE) AND UDTMASK) THEN
                                        FOR redimI2 = 0 TO redimMemberElems - 1
                                            clear_udt_with_varstrings redimPtr$, udtetype(redimE) AND UDTMASK, MainTxtBuf, redimI2 * redimElementBytes
                                        NEXT
                                    ELSE
                                        WriteBufLine MainTxtBuf, "memset((void*)" + redimPtr$ + ",0," + _TOSTR$(redimMemberBytes) + ");"
                                    END IF
                                END IF
                            END IF

                            redimMemberHandled = -1
                        END IF
                    END IF
                END IF

                IF redimMemberHandled THEN
                    IF redimTargetComma <= n THEN
                        l$ = l$ + sp2 + ","
                        i = redimTargetComma + 1
                        IF i > n THEN a$ = "Expected , ...": GOTO errmes
                        GOTO dimnext
                    END IF

                    dimoption = 0
                    dimshared = 0
                    redimoption = 0
                    IF dimstatic = 1 THEN dimstatic = 0
                    AllowLocalName = 0

                    layoutdone = 1
                    IF LEN(layout$) = 0 THEN layout$ = l$ ELSE layout$ = layout$ + sp + l$

                    GOTO finishedline
                END IF

                IF redimoption THEN i = redimTargetFirst
                varname$ = getelement(ca$, i): i = i + 1
                IF varname$ = "" THEN a$ = "Expected " + firstelement$ + " variable-name or " + firstelement$ + " AS type variable-list": GOTO errmes

                'get the next element
                IF i >= n + 1 THEN e$ = "" ELSE e$ = getelement(a$, i): i = i + 1

                'check if next element is a ( to create an array
                elements$ = ""

                IF e$ = "(" THEN
                    B = 1
                    FOR i = i TO n
                        e$ = getelement(ca$, i)
                        IF e$ = "(" THEN B = B + 1
                        IF e$ = ")" THEN B = B - 1
                        IF B = 0 THEN EXIT FOR
                        IF LEN(elements$) THEN elements$ = elements$ + sp + e$ ELSE elements$ = e$
                    NEXT
                    IF B <> 0 THEN a$ = "Expected )": GOTO errmes
                    i = i + 1 'set i to point to the next element

                    IF commonoption THEN elements$ = "?"


                    IF Debug THEN PRINT #9, "DIM2:array:elements$:[" + elements$ + "]"

                    'arrayname() means list array to it will automatically be static when it is formally dimensioned later
                    'note: listed arrays are always created in dynamic memory, but their contents are not erased
                    '      this differs from static arrays from SUB...STATIC and the unique QB64 method -> STATIC arrayname(100)
                    IF dimoption = 3 THEN 'STATIC used
                        IF LEN(elements$) = 0 THEN 'nothing between brackets
                            listarray = 1 'add to static list
                        END IF
                    END IF

                    'last element was ")"
                    'get next element
                    IF i >= n + 1 THEN e$ = "" ELSE e$ = getelement(a$, i): i = i + 1
                END IF 'e$="("
                d$ = e$

                dimmethod = 0

                appendname$ = "" 'the symbol to append to name returned by dim2
                appendtype$ = "" 'eg. sp+AS+spINTEGER
                dim2typepassback$ = ""

                'does varname have an appended symbol?
                s$ = removesymbol$(varname$)
                IF Error_Happened THEN GOTO errmes
                autoIncForceUScore = 1
                IF validname(varname$) = 0 THEN a$ = "Invalid variable name": GOTO errmes

                IF s$ <> "" THEN
                    typ$ = s$
                    dimmethod = 1
                    appendname$ = typ$
                    GOTO dimgottyp
                END IF

                IF d$ = "AS" THEN
                    appendtype$ = sp + SCase$("As")
                    typ$ = ""
                    FOR i = i TO n
                        d$ = getelement(a$, i)
                        IF d$ = "," THEN i = i + 1: EXIT FOR
                        typ$ = typ$ + d$ + " "
                        appendtype$ = appendtype$ + sp + d$
                        d$ = ""
                    NEXT
                    appendtype$ = SCase2$(appendtype$) 'capitalise default types (udt override this later if necessary)
                    typ$ = RTRIM$(typ$)
                    GOTO dimgottyp
                END IF

                'auto-define type based on name
                notype = 1
                IF LEFT$(varname$, 1) = "_" THEN v = 27 ELSE v = ASC(UCASE$(varname$)) - 64
                typ$ = defineaz(v)
                dimmethod = 1
                GOTO dimgottyp

                dimgottyp:
                IF d$ <> "" AND d$ <> "," THEN a$ = "DIM: Expected ,": GOTO errmes

                'In QBASIC, if no type info is given it can refer to an explicit/formally defined array
                IF notype <> 0 AND dimoption <> 3 AND dimoption <> 1 THEN 'not DIM or STATIC which only create new content
                    IF LEN(elements$) THEN 'an array
                        IF FindArray(varname$) THEN
                            IF LEN(RTRIM$(id.mayhave)) THEN 'explicit/formally defined
                                typ$ = id2fulltypename$ 'adopt type
                                dimmethod = 0 'set as formally defined
                            END IF
                        END IF
                    END IF
                END IF

                NormalDimBlock:
                IF dimoption = 3 AND LEN(elements$) THEN 'eg. STATIC a(100)
                    'does a conflicting array exist? (use findarray) if so again this should lead to duplicate definition
                    typ2$ = symbol2fulltypename$(typ$)
                    t = typname2typ(typ2$): ts = typname2typsize
                    'try name without any extension
                    IF FindArray(varname$) THEN 'name without any symbol
                        IF id.insubfuncn = subfuncn THEN 'global cannot conflict with static
                            IF LEN(RTRIM$(id.musthave)) THEN
                                'if types match then fail
                                IF (id.arraytype AND (ISFLOAT + ISUDT + UDTMASK + ISUNSIGNED + ISSTRING + ISFIXEDLENGTH)) = (t AND (ISFLOAT + ISUDT + UDTMASK + ISUNSIGNED + ISSTRING + ISFIXEDLENGTH)) THEN
                                    IF ts = id.tsize THEN
                                        a$ = "Name already in use (" + varname$ + ")": GOTO errmes
                                    END IF
                                END IF
                            ELSE
                                IF dimmethod = 0 THEN
                                    a$ = "Name already in use (" + varname$ + ")": GOTO errmes 'explicit over explicit
                                ELSE
                                    'if types match then fail
                                    IF (id.arraytype AND (ISFLOAT + ISUDT + UDTMASK + ISUNSIGNED + ISSTRING + ISFIXEDLENGTH)) = (t AND (ISFLOAT + ISUDT + UDTMASK + ISUNSIGNED + ISSTRING + ISFIXEDLENGTH)) THEN
                                        IF ts = id.tsize THEN
                                            a$ = "Name already in use (" + varname$ + ")": GOTO errmes
                                        END IF
                                    END IF
                                END IF
                            END IF
                        END IF
                    END IF
                    'add extension (if possible)
                    IF (t AND ISUDT) = 0 THEN
                        s2$ = type2symbol$(typ2$)
                        IF Error_Happened THEN GOTO errmes
                        IF FindArray(varname$ + s2$) THEN
                            IF id.insubfuncn = subfuncn THEN 'global cannot conflict with static
                                IF LEN(RTRIM$(id.musthave)) THEN
                                    'if types match then fail
                                    IF (id.arraytype AND (ISFLOAT + ISUDT + UDTMASK + ISUNSIGNED + ISSTRING + ISFIXEDLENGTH)) = (t AND (ISFLOAT + ISUDT + UDTMASK + ISUNSIGNED + ISSTRING + ISFIXEDLENGTH)) THEN
                                        IF ts = id.tsize THEN
                                            a$ = "Name already in use (" + varname$ + s2$ + ")": GOTO errmes
                                        END IF
                                    END IF
                                ELSE
                                    IF dimmethod = 0 THEN
                                        a$ = "Name already in use (" + varname$ + s2$ + ")": GOTO errmes 'explicit over explicit
                                    ELSE
                                        'if types match then fail
                                        IF (id.arraytype AND (ISFLOAT + ISUDT + UDTMASK + ISUNSIGNED + ISSTRING + ISFIXEDLENGTH)) = (t AND (ISFLOAT + ISUDT + UDTMASK + ISUNSIGNED + ISSTRING + ISFIXEDLENGTH)) THEN
                                            IF ts = id.tsize THEN
                                                a$ = "Name already in use (" + varname$ + s2$ + ")": GOTO errmes
                                            END IF
                                        END IF
                                    END IF
                                END IF
                            END IF
                        END IF
                    END IF 'not a UDT
                END IF

                IF listarray THEN 'eg. STATIC a()
                    'note: list is cleared by END SUB/FUNCTION

                    'is a conflicting array already listed? if so this should cause a duplicate definition error
                    'check for conflict within list:
                    xi = 1
                    FOR x = 1 TO staticarraylistn
                        varname2$ = getelement$(staticarraylist, xi): xi = xi + 1
                        typ2$ = getelement$(staticarraylist, xi): xi = xi + 1
                        dimmethod2 = VAL(getelement$(staticarraylist, xi)): xi = xi + 1
                        'check if they are similar
                        IF UCASE$(varname$) = UCASE$(varname2$) THEN
                            IF dimmethod2 = 1 THEN
                                'old using symbol
                                IF symbol2fulltypename$(typ$) = typ2$ THEN a$ = "Name already in use (" + varname$ + ")": GOTO errmes
                            ELSE
                                'old using AS
                                IF dimmethod = 0 THEN
                                    a$ = "Name already in use (" + varname$ + ")": GOTO errmes
                                ELSE
                                    IF symbol2fulltypename$(typ$) = typ2$ THEN a$ = "Name already in use (" + varname$ + ")": GOTO errmes
                                END IF
                            END IF
                        END IF
                    NEXT

                    'does a conflicting array exist? (use findarray) if so again this should lead to duplicate definition
                    typ2$ = symbol2fulltypename$(typ$)
                    t = typname2typ(typ2$): ts = typname2typsize
                    'try name without any extension
                    IF FindArray(varname$) THEN 'name without any symbol
                        IF id.insubfuncn = subfuncn THEN 'global cannot conflict with static
                            IF LEN(RTRIM$(id.musthave)) THEN
                                'if types match then fail
                                IF (id.arraytype AND (ISFLOAT + ISUDT + UDTMASK + ISUNSIGNED + ISSTRING + ISFIXEDLENGTH)) = (t AND (ISFLOAT + ISUDT + UDTMASK + ISUNSIGNED + ISSTRING + ISFIXEDLENGTH)) THEN
                                    IF ts = id.tsize THEN
                                        a$ = "Name already in use (" + varname$ + ")": GOTO errmes
                                    END IF
                                END IF
                            ELSE
                                IF dimmethod = 0 THEN
                                    a$ = "Name already in use (" + varname$ + ")": GOTO errmes 'explicit over explicit
                                ELSE
                                    'if types match then fail
                                    IF (id.arraytype AND (ISFLOAT + ISUDT + UDTMASK + ISUNSIGNED + ISSTRING + ISFIXEDLENGTH)) = (t AND (ISFLOAT + ISUDT + UDTMASK + ISUNSIGNED + ISSTRING + ISFIXEDLENGTH)) THEN
                                        IF ts = id.tsize THEN
                                            a$ = "Name already in use (" + varname$ + ")": GOTO errmes
                                        END IF
                                    END IF
                                END IF
                            END IF
                        END IF
                    END IF
                    'add extension (if possible)
                    IF (t AND ISUDT) = 0 THEN
                        s2$ = type2symbol$(typ2$)
                        IF Error_Happened THEN GOTO errmes
                        IF FindArray(varname$ + s2$) THEN
                            IF id.insubfuncn = subfuncn THEN 'global cannot conflict with static
                                IF LEN(RTRIM$(id.musthave)) THEN
                                    'if types match then fail
                                    IF (id.arraytype AND (ISFLOAT + ISUDT + UDTMASK + ISUNSIGNED + ISSTRING + ISFIXEDLENGTH)) = (t AND (ISFLOAT + ISUDT + UDTMASK + ISUNSIGNED + ISSTRING + ISFIXEDLENGTH)) THEN
                                        IF ts = id.tsize THEN
                                            a$ = "Name already in use (" + varname$ + s2$ + ")": GOTO errmes
                                        END IF
                                    END IF
                                ELSE
                                    IF dimmethod = 0 THEN
                                        a$ = "Name already in use (" + varname$ + s2$ + ")": GOTO errmes 'explicit over explicit
                                    ELSE
                                        'if types match then fail
                                        IF (id.arraytype AND (ISFLOAT + ISUDT + UDTMASK + ISUNSIGNED + ISSTRING + ISFIXEDLENGTH)) = (t AND (ISFLOAT + ISUDT + UDTMASK + ISUNSIGNED + ISSTRING + ISFIXEDLENGTH)) THEN
                                            IF ts = id.tsize THEN
                                                a$ = "Name already in use (" + varname$ + s2$ + ")": GOTO errmes
                                            END IF
                                        END IF
                                    END IF
                                END IF
                            END IF
                        END IF
                    END IF 'not a UDT

                    'note: static list arrays cannot be created until they are formally [or informally] (RE)DIM'd later
                    IF LEN(staticarraylist) THEN staticarraylist = staticarraylist + sp
                    staticarraylist = staticarraylist + varname$ + sp + symbol2fulltypename$(typ$) + sp + _TOSTR$(dimmethod)
                    IF Error_Happened THEN GOTO errmes
                    staticarraylistn = staticarraylistn + 1
                    l$ = l$ + sp + varname$ + appendname$ + sp2 + "(" + sp2 + ")" + appendtype$
                    'note: none of the following code is run, dim2 call is also skipped

                ELSE

                    olddimstatic = dimstatic

                    'check if varname is on the static list
                    IF LEN(elements$) THEN 'it's an array
                        IF subfuncn THEN 'it's in a sub/function
                            xi = 1
                            FOR x = 1 TO staticarraylistn
                                varname2$ = getelement$(staticarraylist, xi): xi = xi + 1
                                typ2$ = getelement$(staticarraylist, xi): xi = xi + 1
                                dimmethod2 = VAL(getelement$(staticarraylist, xi)): xi = xi + 1
                                'check if they are similar
                                IF UCASE$(varname$) = UCASE$(varname2$) THEN
                                    IF symbol2fulltypename$(typ$) = typ2$ THEN
                                        IF Error_Happened THEN GOTO errmes
                                        IF dimmethod = dimmethod2 THEN
                                            'match found!
                                            varname$ = varname2$
                                            dimstatic = 3
                                            IF dimoption = 3 THEN a$ = "Array already listed as STATIC": GOTO errmes
                                        END IF
                                    END IF 'typ
                                END IF 'varname
                            NEXT
                        END IF
                    END IF

                    'COMMON exception
                    'note: COMMON alone does not imply SHARED
                    '      if either(or both) COMMON & later DIM have SHARED, variable becomes shared
                    IF commonoption THEN
                        IF LEN(elements$) THEN

                            'add array to list
                            IF LEN(commonarraylist) THEN commonarraylist = commonarraylist + sp
                            'note: dimmethod distinguishes between a%(...) vs a(...) AS INTEGER
                            commonarraylist = commonarraylist + varname$ + sp + symbol2fulltypename$(typ$) + sp + _TOSTR$(dimmethod) + sp + _TOSTR$(dimshared)
                            IF Error_Happened THEN GOTO errmes
                            commonarraylistn = commonarraylistn + 1
                            IF Debug THEN PRINT #9, "common listed:" + varname$ + sp + symbol2fulltypename$(typ$) + sp + _TOSTR$(dimmethod) + sp + _TOSTR$(dimshared)
                            IF Error_Happened THEN GOTO errmes

                            x = 0

                            v$ = varname$
                            IF dimmethod = 1 THEN v$ = v$ + typ$
                            try = findid(v$)
                            IF Error_Happened THEN GOTO errmes
                            DO WHILE try
                                IF id.arraytype THEN

                                    t = typname2typ(typ$)
                                    IF Error_Happened THEN GOTO errmes
                                    s = typname2typsize
                                    match = 1
                                    'note: dimmethod 2 is already matched
                                    IF dimmethod = 0 THEN
                                        t2 = id.arraytype
                                        s2 = id.tsize
                                        IF (t AND ISFLOAT) <> (t2 AND ISFLOAT) THEN match = 0
                                        IF (t AND ISUNSIGNED) <> (t2 AND ISUNSIGNED) THEN match = 0
                                        IF (t AND ISSTRING) <> (t2 AND ISSTRING) THEN match = 0
                                        IF (t AND ISFIXEDLENGTH) <> (t2 AND ISFIXEDLENGTH) THEN match = 0
                                        IF (t AND ISOFFSETINBITS) <> (t2 AND ISOFFSETINBITS) THEN match = 0
                                        IF (t AND ISUDT) <> (t2 AND ISUDT) THEN match = 0
                                        IF (t AND UDTMASK) <> (t2 AND UDTMASK) THEN match = 0
                                        IF s <> s2 THEN match = 0
                                        'check for implicit/explicit declaration match
                                        oldmethod = 0: IF LEN(RTRIM$(id.musthave)) THEN oldmethod = 1
                                        IF oldmethod <> dimmethod THEN match = 0
                                    END IF

                                    IF match THEN
                                        x = currentid
                                        IF dimshared THEN ids(x).share = 1 'share if necessary
                                        tlayout$ = RTRIM$(id.cn) + sp + "(" + sp2 + ")"

                                        IF dimmethod = 0 THEN
                                            IF t AND ISUDT THEN
                                                dim2typepassback$ = RTRIM$(udtxcname(t AND UDTMASK))
                                            ELSE
                                                dim2typepassback$ = typ$
                                                DO WHILE INSTR(dim2typepassback$, " ")
                                                    ASC(dim2typepassback$, INSTR(dim2typepassback$, " ")) = ASC(sp)
                                                LOOP
                                                dim2typepassback$ = SCase2$(dim2typepassback$)
                                            END IF
                                        END IF 'method 0

                                        EXIT DO
                                    END IF 'match

                                END IF 'arraytype
                                IF try = 2 THEN findanotherid = 1: try = findid(v$) ELSE try = 0
                                IF Error_Happened THEN GOTO errmes
                            LOOP

                            IF x = 0 THEN x = idn + 1

                            'note: the following code only adds include directives, everything else is deferred
                            ChainTxtBuf = OpenBuffer%("A", tmpdir$ + "chain.txt")
                            'include directive
                            WriteBufLine ChainTxtBuf, "#include " + CHR$(34) + "chain" + _TOSTR$(x) + ".txt" + CHR$(34)
                            'create/clear include file
                            ChainTxtBuf = OpenBuffer%("O", tmpdir$ + "chain" + _TOSTR$(x) + ".txt")

                            ChainTxtBuf = OpenBuffer%("A", tmpdir$ + "inpchain.txt")
                            'include directive
                            WriteBufLine ChainTxtBuf, "#include " + CHR$(34) + "inpchain" + _TOSTR$(x) + ".txt" + CHR$(34)
                            'create/clear include file
                            ChainTxtBuf = OpenBuffer%("O", tmpdir$ + "inpchain" + _TOSTR$(x) + ".txt")

                            'note: elements$="?"
                            IF x <> idn + 1 THEN GOTO skipdim 'array already exists
                            GOTO dimcommonarray

                        END IF
                    END IF

                    'is varname on common list?
                    '******
                    IF LEN(elements$) THEN 'it's an array
                        IF subfuncn = 0 THEN 'not in a sub/function

                            IF Debug THEN PRINT #9, "common checking:" + varname$

                            xi = 1
                            FOR x = 1 TO commonarraylistn
                                varname2$ = getelement$(commonarraylist, xi): xi = xi + 1
                                typ2$ = getelement$(commonarraylist, xi): xi = xi + 1
                                dimmethod2 = VAL(getelement$(commonarraylist, xi)): xi = xi + 1
                                dimshared2 = VAL(getelement$(commonarraylist, xi)): xi = xi + 1
                                IF Debug THEN PRINT #9, "common checking against:" + varname2$ + sp + typ2$ + sp + _TOSTR$(dimmethod2) + sp + _TOSTR$(dimshared2)
                                'check if they are similar
                                IF varname$ = varname2$ THEN
                                    IF symbol2fulltypename$(typ$) = typ2$ THEN
                                        IF Error_Happened THEN GOTO errmes
                                        IF dimmethod = dimmethod2 THEN

                                            'match found!
                                            'enforce shared status (if necessary)
                                            IF dimshared2 THEN dimshared = dimshared OR 2 'temp force SHARED

                                            'old chain code
                                            'chaincommonarray=x

                                        END IF 'method
                                    END IF 'typ
                                END IF 'varname
                            NEXT
                        END IF
                    END IF

                    dimcommonarray:
                    retval = dim2(varname$, typ$, dimmethod, elements$)
                    IF Error_Happened THEN GOTO errmes
                    skipdim:
                    IF dimshared >= 2 THEN dimshared = dimshared - 2

                    'non-array COMMON variable
                    IF commonoption <> 0 AND LEN(elements$) = 0 THEN

                        'CHAIN.TXT (save)

                        use_global_byte_elements = 1

                        'switch output from main to chain.txt
                        maintxtbufprev = MainTxtBuf
                        MainTxtBuf = OpenBuffer%("A", tmpdir$ + "chain.txt")
                        l2$ = tlayout$

                        WriteBufLine MainTxtBuf, "int32val=1;" 'simple variable
                        WriteBufLine MainTxtBuf, "sub_put(FF,NULL,byte_element((uint64)&int32val,4," + NewByteElement$ + "),0);"

                        t = id.t
                        bits = t AND UDTMASK
                        IF t AND ISUDT THEN bits = udtxsize(t AND UDTMASK)
                        IF t AND ISSTRING THEN
                            IF t AND ISFIXEDLENGTH THEN
                                bits = id.tsize * 8
                            ELSE
                                WriteBufLine MainTxtBuf, "int64val=__STRING_" + RTRIM$(id.n) + "->len*8;"
                                bits = 0
                            END IF
                        END IF

                        IF bits THEN
                            WriteBufLine MainTxtBuf, "int64val=" + _TOSTR$(bits) + ";" 'size in bits
                        END IF
                        WriteBufLine MainTxtBuf, "sub_put(FF,NULL,byte_element((uint64)&int64val,8," + NewByteElement$ + "),0);"

                        'put the variable
                        e$ = RTRIM$(id.n)

                        IF (t AND ISUDT) = 0 THEN
                            IF t AND ISFIXEDLENGTH THEN
                                e$ = e$ + "$" + _TOSTR$(id.tsize)
                            ELSE
                                e$ = e$ + typevalue2symbol$(t)
                                IF Error_Happened THEN GOTO errmes
                            END IF
                        END IF
                        e$ = evaluatetotyp(fixoperationorder$(e$), -4)
                        IF Error_Happened THEN GOTO errmes

                        WriteBufLine MainTxtBuf, "sub_put(FF,NULL," + e$ + ",0);"

                        tlayout$ = l2$

                        'INPCHAIN.TXT (load)

                        'switch output from chain.txt to inpchain.txt
                        MainTxtBuf = OpenBuffer%("A", tmpdir$ + "inpchain.txt")
                        l2$ = tlayout$


                        WriteBufLine MainTxtBuf, "if (int32val==1){"
                        'get the size in bits
                        WriteBufLine MainTxtBuf, "sub_get(FF,NULL,byte_element((uint64)&int64val,8," + NewByteElement$ + "),0);"
                        '***assume correct size***

                        e$ = RTRIM$(id.n)
                        t = id.t
                        IF (t AND ISUDT) = 0 THEN
                            IF t AND ISFIXEDLENGTH THEN
                                e$ = e$ + "$" + _TOSTR$(id.tsize)
                            ELSE
                                e$ = e$ + typevalue2symbol$(t)
                                IF Error_Happened THEN GOTO errmes
                            END IF
                        END IF

                        IF t AND ISSTRING THEN
                            IF (t AND ISFIXEDLENGTH) = 0 THEN
                                WriteBufLine MainTxtBuf, "tqbs=qbs_new(int64val>>3,1);"
                                WriteBufLine MainTxtBuf, "qbs_set(__STRING_" + RTRIM$(id.n) + ",tqbs);"
                                'now that the string is the correct size, the following GET command will work correctly...
                            END IF
                        END IF

                        e$ = evaluatetotyp(fixoperationorder$(e$), -4)
                        IF Error_Happened THEN GOTO errmes
                        WriteBufLine MainTxtBuf, "sub_get(FF,NULL," + e$ + ",0);"

                        WriteBufLine MainTxtBuf, "sub_get(FF,NULL,byte_element((uint64)&int32val,4," + NewByteElement$ + "),0);" 'get next command
                        WriteBufLine MainTxtBuf, "}"

                        tlayout$ = l2$
                        'revert output to main
                        MainTxtBuf = maintxtbufprev

                        use_global_byte_elements = 0

                    END IF

                    commonarraylisted:

                    IF LEN(appendtype$) > 0 AND newDimSyntax = -1 THEN
                        IF LEN(dim2typepassback$) THEN appendtype$ = sp + SCase$("As") + sp + dim2typepassback$
                        IF newDimSyntaxTypePassBack = 0 THEN
                            newDimSyntaxTypePassBack = -1
                            l$ = l$ + appendtype$
                        END IF
                    END IF

                    n2 = numelements(tlayout$)
                    l$ = l$ + sp + getelement$(tlayout$, 1) + appendname$
                    IF n2 > 1 THEN
                        l$ = l$ + sp2 + getelements$(tlayout$, 2, n2)
                    END IF

                    IF LEN(appendtype$) > 0 AND newDimSyntax = 0 THEN
                        IF LEN(dim2typepassback$) THEN appendtype$ = sp + SCase$("As") + sp + dim2typepassback$
                        l$ = l$ + appendtype$
                    END IF

                    'modify first element name to include symbol

                    dimstatic = olddimstatic

                END IF 'listarray=0

                IF newDimSyntax THEN RETURN

                IF d$ = "," THEN l$ = l$ + sp2 + ",": GOTO dimnext

                dimoption = 0
                dimshared = 0
                redimoption = 0
                IF dimstatic = 1 THEN dimstatic = 0
                AllowLocalName = 0

                layoutdone = 1
                IF LEN(layout$) = 0 THEN layout$ = l$ ELSE layout$ = layout$ + sp + l$

                GOTO finishedline
            ELSE
                'yes, this is the new dim syntax.
                i = i + 1 'skip "AS"
                newDimSyntaxTypePassBack = 0

                'establish the data type:
                appendname$ = ""
                appendtype$ = sp + SCase$("As")
                typ$ = ""
                varname$ = ""
                previousElement$ = ""
                FOR i = i TO n
                    d$ = getelement(a$, i)
                    IF d$ = "," OR d$ = "(" THEN EXIT FOR
                    varname$ = getelement(ca$, i)
                    IF LEN(previousElement$) THEN
                        typ$ = typ$ + previousElement$ + " "
                        appendtype$ = appendtype$ + sp + previousElement$
                    END IF
                    previousElement$ = d$
                    d$ = ""
                NEXT
                appendtype$ = SCase2$(appendtype$) 'capitalise default types (udt override this later if necessary)
                typ$ = RTRIM$(typ$)

                dimnext2:
                notype = 0
                listarray = 0

                IF typ$ = "" OR varname$ = "" THEN a$ = "Expected " + firstelement$ + " AS type variable-list or " + firstelement$ + " variable-name AS type": GOTO errmes

                'get the next element
                IF i >= n + 1 THEN e$ = "" ELSE e$ = getelement(a$, i): i = i + 1

                'check if next element is a ( to create an array
                elements$ = ""

                IF e$ = "(" THEN
                    B = 1
                    FOR i = i TO n
                        e$ = getelement(ca$, i)
                        IF e$ = "(" THEN B = B + 1
                        IF e$ = ")" THEN B = B - 1
                        IF B = 0 THEN EXIT FOR
                        IF LEN(elements$) THEN elements$ = elements$ + sp + e$ ELSE elements$ = e$
                    NEXT
                    IF B <> 0 THEN a$ = "Expected )": GOTO errmes
                    i = i + 1 'set i to point to the next element

                    IF commonoption THEN elements$ = "?"


                    IF Debug THEN PRINT #9, "DIM2:array:elements$:[" + elements$ + "]"

                    'arrayname() means list array to it will automatically be static when it is formally dimensioned later
                    'note: listed arrays are always created in dynamic memory, but their contents are not erased
                    '      this differs from static arrays from SUB...STATIC and the unique QB64 method -> STATIC arrayname(100)
                    IF dimoption = 3 THEN 'STATIC used
                        IF LEN(elements$) = 0 THEN 'nothing between brackets
                            listarray = 1 'add to static list
                        END IF
                    END IF

                    'last element was ")"
                    'get next element
                    IF i >= n + 1 THEN e$ = "" ELSE e$ = getelement(a$, i): i = i + 1
                END IF 'e$="("
                d$ = e$

                dimmethod = 0

                dim2typepassback$ = ""

                'does varname have an appended symbol?
                s$ = removesymbol$(varname$)
                IF Error_Happened THEN GOTO errmes
                autoIncForceUScore = 1
                IF validname(varname$) = 0 THEN a$ = "Invalid variable name": GOTO errmes

                IF s$ <> "" THEN
                    a$ = "Cannot use type symbol with " + firstelement$ + " AS type variable-list (" + s$ + ")"
                    GOTO errmes
                END IF

                IF d$ <> "" AND d$ <> "," THEN a$ = "DIM: Expected ,": GOTO errmes

                newDimSyntax = -1
                GOSUB NormalDimBlock
                newDimSyntax = 0

                IF d$ = "," THEN
                    l$ = l$ + sp2 + ","
                    varname$ = getelement(ca$, i): i = i + 1
                    GOTO dimnext2
                END IF

                dimoption = 0
                dimshared = 0
                redimoption = 0
                IF dimstatic = 1 THEN dimstatic = 0
                AllowLocalName = 0

                layoutdone = 1
                IF LEN(layout$) = 0 THEN layout$ = l$ ELSE layout$ = layout$ + sp + l$

                GOTO finishedline
            END IF
        END IF
    END IF











    'THEN [GOTO] linenumber?
    IF THENGOTO = 1 THEN
        IF n = 1 THEN
            l$ = ""
            a = ASC(LEFT$(firstelement$, 1))
            IF a = 46 OR (a >= 48 AND a <= 57) THEN a2$ = ca$: GOTO THENGOTO
        END IF
    END IF

    'goto
    IF n = 2 THEN
        IF getelement$(a$, 1) = "GOTO" THEN
            l$ = SCase$("GoTo")
            a2$ = getelement$(ca$, 2)
            THENGOTO:
            IF validlabel(a2$) = 0 THEN a$ = "Invalid label!": GOTO errmes

            v = HashFind(a2$, HASHFLAG_LABEL, ignore, r)
            x = 1
            labchk2:
            IF v THEN
                s = Labels(r).Scope
                IF s = subfuncn OR s = -1 THEN 'same scope?
                    IF s = -1 THEN Labels(r).Scope = subfuncn 'acquire scope
                    x = 0 'already defined
                    tlayout$ = RTRIM$(Labels(r).cn)
                ELSE
                    IF v = 2 THEN v = HashFindCont(ignore, r): GOTO labchk2
                END IF
            END IF
            IF x THEN
                'does not exist
                nLabels = nLabels + 1: IF nLabels > Labels_Ubound THEN Labels_Ubound = Labels_Ubound * 2: REDIM _PRESERVE Labels(1 TO Labels_Ubound) AS Label_Type
                Labels(nLabels) = Empty_Label
                HashAdd a2$, HASHFLAG_LABEL, nLabels
                r = nLabels
                Labels(r).State = 0
                Labels(r).cn = tlayout$
                Labels(r).Scope = subfuncn
                Labels(r).Error_Line = linenumber
            END IF 'x

            IF LEN(l$) THEN l$ = l$ + sp + tlayout$ ELSE l$ = tlayout$
            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
            WriteBufLine MainTxtBuf, "goto LABEL_" + a2$ + ";"
            GOTO finishedline
        END IF
    END IF

    IF n = 1 THEN
        IF firstelement$ = "_CONTINUE" THEN
            l$ = SCase$("_Continue")
            'scan backwards until previous control level reached
            FOR i = controllevel TO 1 STEP -1
                t = controltype(i)
                IF t = 2 THEN 'for...next
                    WriteBufLine MainTxtBuf, "goto fornext_continue_" + _TOSTR$(controlid(i)) + ";"
                    layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                    GOTO finishedline
                ELSEIF t = 3 OR t = 4 THEN 'do...loop
                    WriteBufLine MainTxtBuf, "goto dl_continue_" + _TOSTR$(controlid(i)) + ";"
                    layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                    GOTO finishedline
                ELSEIF t = 5 THEN 'while...wend
                    WriteBufLine MainTxtBuf, "goto ww_continue_" + _TOSTR$(controlid(i)) + ";"
                    layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                    GOTO finishedline
                END IF
            NEXT
            a$ = "_CONTINUE outside DO..LOOP/FOR..NEXT/WHILE..WEND block": GOTO errmes
        END IF
    END IF

    IF firstelement$ = "CHAIN" THEN
        IF GetRCStateVar(vWatchOn) THEN
            addWarning linenumber, inclevel, inclinenumber(inclevel), incname$(inclevel), "Feature incompatible with $DEBUG mode", "CHAIN"
        END IF
    END IF

    IF firstelement$ = "RUN" THEN 'RUN
        IF GetRCStateVar(vWatchOn) THEN
            addWarning linenumber, inclevel, inclinenumber(inclevel), incname$(inclevel), "Feature incompatible with $DEBUG mode", "RUN"
        END IF
        l$ = SCase$("Run")
        IF n = 1 THEN
            'no parameters
            WriteBufLine MainTxtBuf, "sub_run_init();" 'note: called first to free up screen-locked image handles
            WriteBufLine MainTxtBuf, "sub_clear(NULL,NULL,NULL,NULL);" 'use functionality of CLEAR
            IF LEN(subfunc$) THEN
                WriteBufLine MainTxtBuf, "QBMAIN(NULL);"
            ELSE
                WriteBufLine MainTxtBuf, "goto S_0;"
            END IF
        ELSE
            'parameter passed
            e$ = getelements$(ca$, 2, n)
            e$ = fixoperationorder$(e$)
            IF Error_Happened THEN GOTO errmes
            l2$ = tlayout$
            ignore$ = evaluate(e$, typ)
            IF Error_Happened THEN GOTO errmes
            IF n = 2 AND ((typ AND ISSTRING) = 0) THEN
                'assume it's a label or line number
                lbl$ = getelement$(ca$, 2)
                IF validlabel(lbl$) = 0 THEN a$ = "Invalid label!": GOTO errmes 'invalid label

                v = HashFind(lbl$, HASHFLAG_LABEL, ignore, r)
                x = 1
                labchk501:
                IF v THEN
                    s = Labels(r).Scope
                    IF s = 0 OR s = -1 THEN 'main scope?
                        IF s = -1 THEN Labels(r).Scope = 0 'acquire scope
                        x = 0 'already defined
                        tlayout$ = RTRIM$(Labels(r).cn)
                        Labels(r).Scope_Restriction = subfuncn
                        Labels(r).Error_Line = linenumber
                    ELSE
                        IF v = 2 THEN v = HashFindCont(ignore, r): GOTO labchk501
                    END IF
                END IF
                IF x THEN
                    'does not exist
                    nLabels = nLabels + 1: IF nLabels > Labels_Ubound THEN Labels_Ubound = Labels_Ubound * 2: REDIM _PRESERVE Labels(1 TO Labels_Ubound) AS Label_Type
                    Labels(nLabels) = Empty_Label
                    HashAdd lbl$, HASHFLAG_LABEL, nLabels
                    r = nLabels
                    Labels(r).State = 0
                    Labels(r).cn = tlayout$
                    Labels(r).Scope = 0
                    Labels(r).Error_Line = linenumber
                    Labels(r).Scope_Restriction = subfuncn
                END IF 'x

                l$ = l$ + sp + tlayout$
                WriteBufLine MainTxtBuf, "sub_run_init();" 'note: called first to free up screen-locked image handles
                WriteBufLine MainTxtBuf, "sub_clear(NULL,NULL,NULL,NULL);" 'use functionality of CLEAR
                IF LEN(subfunc$) THEN
                    WriteBufLine RunTxtBuf, "if (run_from_line==" + _TOSTR$(nextrunlineindex) + "){run_from_line=0;goto LABEL_" + lbl$ + ";}"
                    WriteBufLine MainTxtBuf, "run_from_line=" + _TOSTR$(nextrunlineindex) + ";"
                    nextrunlineindex = nextrunlineindex + 1
                    WriteBufLine MainTxtBuf, "QBMAIN(NULL);"
                ELSE
                    WriteBufLine MainTxtBuf, "goto LABEL_" + lbl$ + ";"
                END IF
            ELSE
                'assume it's a string containing a filename to execute
                e$ = evaluatetotyp(e$, ISSTRING)
                IF Error_Happened THEN GOTO errmes
                WriteBufLine MainTxtBuf, "sub_run(" + e$ + ");"
                l$ = l$ + sp + l2$
            END IF 'isstring
        END IF 'n=1
        layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
        GOTO finishedline
    END IF 'run





    IF firstelement$ = "END" THEN
        l$ = SCase$("End")
        IF n > 1 THEN
            e$ = getelements$(ca$, 2, n)
            e$ = fixoperationorder$(e$): IF Error_Happened THEN GOTO errmes
            l2$ = tlayout$
            e$ = evaluatetotyp(e$, ISINTEGER64): IF Error_Happened THEN GOTO errmes
            inclinenump$ = ""
            IF inclinenumber(inclevel) THEN
                inclinenump$ = "," + _TOSTR$(inclinenumber(inclevel))
                thisincname$ = getfilepath$(incname$(inclevel))
                thisincname$ = MID$(incname$(inclevel), LEN(thisincname$) + 1)
                inclinenump$ = inclinenump$ + "," + CHR$(34) + thisincname$ + CHR$(34)
            END IF
            IF GetRCStateVar(vWatchOn) = 1 AND inclinenumber(inclevel) = 0 THEN temp$ = vWatchErrorCall$ ELSE temp$ = ""
            WriteBufLine MainTxtBuf, "if(qbevent){" + temp$ + "evnt(" + _TOSTR$(linenumber) + inclinenump$ + ");}" 'non-resumable error check (cannot exit without handling errors)
            WriteBufLine MainTxtBuf, "exit_code=" + e$ + ";"
            l$ = l$ + sp + l2$
        END IF
        xend
        layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
        GOTO finishedline
    END IF

    IF firstelement$ = "SYSTEM" THEN
        l$ = SCase$("System")
        IF n > 1 THEN
            e$ = getelements$(ca$, 2, n)
            e$ = fixoperationorder$(e$): IF Error_Happened THEN GOTO errmes
            l2$ = tlayout$
            e$ = evaluatetotyp(e$, ISINTEGER64): IF Error_Happened THEN GOTO errmes
            inclinenump$ = ""
            IF inclinenumber(inclevel) THEN
                inclinenump$ = "," + _TOSTR$(inclinenumber(inclevel))
                thisincname$ = getfilepath$(incname$(inclevel))
                thisincname$ = MID$(incname$(inclevel), LEN(thisincname$) + 1)
                inclinenump$ = inclinenump$ + "," + CHR$(34) + thisincname$ + CHR$(34)
            END IF
            IF GetRCStateVar(vWatchOn) = 1 AND CheckingOn = 1 AND inclinenumber(inclevel) = 0 THEN temp$ = vWatchErrorCall$ ELSE temp$ = ""
            WriteBufLine MainTxtBuf, "if(qbevent){" + temp$ + "evnt(" + _TOSTR$(linenumber) + inclinenump$ + ");}" 'non-resumable error check (cannot exit without handling errors)
            WriteBufLine MainTxtBuf, "exit_code=" + e$ + ";"
            l$ = l$ + sp + l2$
        END IF


        IF GetRCStateVar(vWatchOn) THEN
            IF inclinenumber(inclevel) = 0 THEN
                vWatchAddLabel linenumber, 0
            END IF
            WriteBufLine MainTxtBuf, "*__LONG_VWATCH_LINENUMBER= 0; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars);"
        END IF
        WriteBufLine MainTxtBuf, "if (sub_gl_called) error(271);"
        WriteBufLine MainTxtBuf, "close_program=1;"
        WriteBufLine MainTxtBuf, "end();"
        layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
        GOTO finishedline
    END IF

    IF n >= 1 THEN
        IF firstelement$ = "STOP" THEN
            l$ = SCase$("Stop")
            IF n > 1 THEN
                e$ = getelements$(ca$, 2, n)
                e$ = fixoperationorder$(e$)
                IF Error_Happened THEN GOTO errmes
                l$ = SCase$("Stop") + sp + tlayout$
                e$ = evaluatetotyp(e$, 64)
                IF Error_Happened THEN GOTO errmes
                'note: this value is currently ignored but evaluated for checking reasons
            END IF
            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
            IF GetRCStateVar(vWatchOn) = 1 AND CheckingOn = 1 AND inclinenumber(inclevel) = 0 THEN
                WriteBufLine MainTxtBuf, "*__LONG_VWATCH_LINENUMBER=-3; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars); if (*__LONG_VWATCH_GOTO>0) goto VWATCH_SETNEXTLINE; if (*__LONG_VWATCH_GOTO<0) goto VWATCH_SKIPLINE;"
                vWatchAddLabel linenumber, 0
            ELSE
                WriteBufLine MainTxtBuf, "close_program=1;"
                WriteBufLine MainTxtBuf, "end();"
            END IF
            GOTO finishedline
        END IF
    END IF

    IF n = 2 THEN
        IF firstelement$ = "GOSUB" THEN
            xgosub ca$
            IF Error_Happened THEN GOTO errmes
            'note: layout implemented in xgosub
            GOTO finishedline
        END IF
    END IF

    IF n >= 1 THEN
        IF firstelement$ = "RETURN" THEN
            IF n = 1 THEN
                WriteBufLine MainTxtBuf, "#include " + CHR$(34) + "ret" + _TOSTR$(subfuncn) + ".txt" + CHR$(34)
                l$ = SCase$("Return")
                layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                GOTO finishedline
            ELSE
                'label/linenumber follows
                IF subfuncn <> 0 THEN a$ = "RETURN linelabel/linenumber invalid within a SUB/FUNCTION": GOTO errmes
                IF n > 2 THEN a$ = "Expected linelabel/linenumber after RETURN": GOTO errmes
                WriteBufLine MainTxtBuf, "if (!next_return_point) error(3);" 'check return point available
                WriteBufLine MainTxtBuf, "next_return_point--;" 'destroy return point
                a2$ = getelement$(ca$, 2)
                IF validlabel(a2$) = 0 THEN a$ = "Invalid label!": GOTO errmes

                v = HashFind(a2$, HASHFLAG_LABEL, ignore, r)
                x = 1
                labchk505:
                IF v THEN
                    s = Labels(r).Scope
                    IF s = subfuncn OR s = -1 THEN 'same scope?
                        IF s = -1 THEN Labels(r).Scope = subfuncn 'acquire scope
                        x = 0 'already defined
                        tlayout$ = RTRIM$(Labels(r).cn)
                    ELSE
                        IF v = 2 THEN v = HashFindCont(ignore, r): GOTO labchk505
                    END IF
                END IF
                IF x THEN
                    'does not exist
                    nLabels = nLabels + 1: IF nLabels > Labels_Ubound THEN Labels_Ubound = Labels_Ubound * 2: REDIM _PRESERVE Labels(1 TO Labels_Ubound) AS Label_Type
                    Labels(nLabels) = Empty_Label
                    HashAdd a2$, HASHFLAG_LABEL, nLabels
                    r = nLabels
                    Labels(r).State = 0
                    Labels(r).cn = tlayout$
                    Labels(r).Scope = subfuncn
                    Labels(r).Error_Line = linenumber
                END IF 'x

                WriteBufLine MainTxtBuf, "goto LABEL_" + a2$ + ";"
                l$ = SCase$("Return") + sp + tlayout$
                layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                GOTO finishedline
            END IF
        END IF
    END IF

    IF n >= 1 THEN
        IF firstelement$ = "RESUME" THEN
            l$ = SCase$("Resume")
            IF n = 1 THEN
                resumeprev:


                WriteBufLine MainTxtBuf, "if (!error_handling){error(20);}else{error_retry=1; qbevent=1; error_handling=0; error_err=0; return;}"

                layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                GOTO finishedline
            END IF
            IF n > 2 THEN a$ = "Too many parameters": GOTO errmes
            s$ = getelement$(ca$, 2)
            IF UCASE$(s$) = "NEXT" THEN


                WriteBufLine MainTxtBuf, "if (!error_handling){error(20);}else{error_handling=0; error_err=0; return;}"

                l$ = l$ + sp + SCase$("Next")
                layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                GOTO finishedline
            END IF
            IF s$ = "0" THEN l$ = l$ + sp + "0": GOTO resumeprev
            IF validlabel(s$) = 0 THEN a$ = "Invalid label passed to RESUME": GOTO errmes

            v = HashFind(s$, HASHFLAG_LABEL, ignore, r)
            x = 1
            labchk506:
            IF v THEN
                s = Labels(r).Scope
                IF s = subfuncn OR s = -1 THEN 'same scope?
                    IF s = -1 THEN Labels(r).Scope = subfuncn 'acquire scope
                    x = 0 'already defined
                    tlayout$ = RTRIM$(Labels(r).cn)
                ELSE
                    IF v = 2 THEN v = HashFindCont(ignore, r): GOTO labchk506
                END IF
            END IF
            IF x THEN
                'does not exist
                nLabels = nLabels + 1: IF nLabels > Labels_Ubound THEN Labels_Ubound = Labels_Ubound * 2: REDIM _PRESERVE Labels(1 TO Labels_Ubound) AS Label_Type
                Labels(nLabels) = Empty_Label
                HashAdd s$, HASHFLAG_LABEL, nLabels
                r = nLabels
                Labels(r).State = 0
                Labels(r).cn = tlayout$
                Labels(r).Scope = subfuncn
                Labels(r).Error_Line = linenumber
            END IF 'x

            l$ = l$ + sp + tlayout$
            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
            WriteBufLine MainTxtBuf, "if (!error_handling){error(20);}else{error_handling=0; error_err=0; goto LABEL_" + s$ + ";}"
            GOTO finishedline
        END IF
    END IF

    IF n = 4 OR n = 5 THEN
        IF getelements(a$, 1, 3) = "ON" + sp + "ERROR" + sp + "GOTO" THEN
            l$ = SCase$("On" + sp + "Error" + sp + "GoTo")
            lbl$ = getelement$(ca$, 4)
            hhc$ = UCASE$(lbl$) '(H)andler(H)istory(C)ommand
            IF n = 5 THEN
                IF hhc$ = "_LASTHANDLER" THEN a$ = "No label allowed after _LASTHANDLER": GOTO errmes
                IF hhc$ <> "_NEWHANDLER" THEN a$ = "Expected: ON ERROR GOTO [_NEWHANDLER] label": GOTO errmes
                lbl$ = getelement$(ca$, 5)
                IF lbl$ = "0" THEN a$ = "Zero not allowed after _NEWHANDLER": GOTO errmes
            END IF
            IF lbl$ = "0" THEN 'independent from hhc$ (i.e. always clear history)
                WriteBufLine MainTxtBuf, "error_goto_line=0;"
                WriteBufLine MainTxtBuf, "qbs_set(error_handler_history, qbs_new_txt_len(" + MKI$(&H2222) + ", 0));"
                WriteBufLine MainTxtBuf, "qbs_cleanup(qbs_tmp_base, 0);"
                l$ = l$ + sp + "0"
                layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                GOTO finishedline
            ELSEIF hhc$ = "_NEWHANDLER" THEN
                IF n = 4 THEN a$ = "Expected: ON ERROR GOTO [_NEWHANDLER] label": GOTO errmes
                l$ = l$ + sp + SCase$("_NewHandler")
            ELSEIF hhc$ = "_LASTHANDLER" THEN
                WriteBufLine MainTxtBuf, "error_goto_line = qbr(qbs_val<uint64_t>(error_handler_history));"
                WriteBufLine MainTxtBuf, "qbs_set(error_handler_history, func_mid(error_handler_history, func_instr(NULL, error_handler_history, qbs_new_txt_len(" + CHR$(34) + "|" + CHR$(34) + ", 1), 0) + 1 , NULL, 0));"
                WriteBufLine MainTxtBuf, "qbs_cleanup(qbs_tmp_base, 0);"
                l$ = l$ + sp + SCase$("_LastHandler")
                layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                GOTO finishedline
            END IF
            IF validlabel(lbl$) = 0 THEN a$ = "Invalid label": GOTO errmes

            v = HashFind(lbl$, HASHFLAG_LABEL, ignore, r)
            x = 1
            labchk6:
            IF v THEN
                s = Labels(r).Scope
                IF s = 0 OR s = -1 THEN 'main scope?
                    IF s = -1 THEN Labels(r).Scope = 0 'acquire scope
                    x = 0 'already defined
                    tlayout$ = RTRIM$(Labels(r).cn)
                    Labels(r).Scope_Restriction = subfuncn
                    Labels(r).Error_Line = linenumber
                ELSE
                    IF v = 2 THEN v = HashFindCont(ignore, r): GOTO labchk6
                END IF
            END IF
            IF x THEN
                'does not exist
                nLabels = nLabels + 1: IF nLabels > Labels_Ubound THEN Labels_Ubound = Labels_Ubound * 2: REDIM _PRESERVE Labels(1 TO Labels_Ubound) AS Label_Type
                Labels(nLabels) = Empty_Label
                HashAdd lbl$, HASHFLAG_LABEL, nLabels
                r = nLabels
                Labels(r).State = 0
                Labels(r).cn = tlayout$
                Labels(r).Scope = 0
                Labels(r).Error_Line = linenumber
                Labels(r).Scope_Restriction = subfuncn
            END IF 'x

            l$ = l$ + sp + tlayout$
            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
            errorlabels = errorlabels + 1
            IF hhc$ = "_NEWHANDLER" THEN
                WriteBufLine MainTxtBuf, "qbs_set(error_handler_history, qbs_add(qbs_add(qbs_str((int32)(error_goto_line)), qbs_new_txt_len(" + CHR$(34) + "|" + CHR$(34) + ", 1)), error_handler_history));"
                WriteBufLine MainTxtBuf, "qbs_cleanup(qbs_tmp_base, 0);"
            END IF
            WriteBufLine MainTxtBuf, "error_goto_line=" + _TOSTR$(errorlabels) + ";"
            WriteBufLine ErrTxtBuf, "if (error_goto_line==" + _TOSTR$(errorlabels) + "){error_handling=1; goto LABEL_" + lbl$ + ";}"
            GOTO finishedline
        END IF
    END IF

    IF n >= 1 THEN
        IF firstelement$ = "RESTORE" THEN
            l$ = SCase$("Restore")
            IF n = 1 THEN
                WriteBufLine MainTxtBuf, "data_offset=0;"
            ELSE
                IF n > 2 THEN a$ = "Syntax error - too many parameters (expected RESTORE label/line number)": GOTO errmes
                lbl$ = getelement$(ca$, 2)
                IF validlabel(lbl$) = 0 THEN a$ = "Invalid label": GOTO errmes

                'rule: a RESTORE label has no scope, therefore, only one instance of that label may exist
                'how: enforced by a post check for duplicates
                v = HashFind(lbl$, HASHFLAG_LABEL, ignore, r)
                x = 1
                IF v THEN 'already defined
                    x = 0
                    tlayout$ = RTRIM$(Labels(r).cn)
                    Labels(r).Data_Referenced = 1 'make sure the data referenced flag is set
                    IF Labels(r).Error_Line = 0 THEN Labels(r).Error_Line = linenumber
                END IF
                IF x THEN
                    nLabels = nLabels + 1: IF nLabels > Labels_Ubound THEN Labels_Ubound = Labels_Ubound * 2: REDIM _PRESERVE Labels(1 TO Labels_Ubound) AS Label_Type
                    Labels(nLabels) = Empty_Label
                    HashAdd lbl$, HASHFLAG_LABEL, nLabels
                    r = nLabels
                    Labels(r).State = 0
                    Labels(r).cn = tlayout$
                    Labels(r).Scope = -1 'modifiable scope
                    Labels(r).Error_Line = linenumber
                    Labels(r).Data_Referenced = 1
                END IF 'x

                l$ = l$ + sp + tlayout$
                WriteBufLine MainTxtBuf, "data_offset=data_at_LABEL_" + lbl$ + ";"
            END IF
            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
            GOTO finishedline
        END IF
    END IF



    'ON ... GOTO/GOSUB
    IF n >= 1 THEN
        IF firstelement$ = "ON" THEN
            xongotogosub a$, ca$, n
            IF Error_Happened THEN GOTO errmes
            GOTO finishedline
        END IF
    END IF


    '(_MEM) _MEMPUT _MEMGET
    IF n >= 1 THEN
        IF firstelement$ = "_MEMGET" THEN
            'get expressions
            e$ = ""
            B = 0
            ne = 0
            FOR i2 = 2 TO n
                e2$ = getelement$(ca$, i2)
                IF e2$ = "(" THEN B = B + 1
                IF e2$ = ")" THEN B = B - 1
                IF e2$ = "," AND B = 0 THEN
                    ne = ne + 1
                    IF ne = 1 THEN blk$ = e$: e$ = ""
                    IF ne = 2 THEN offs$ = e$: e$ = ""
                    IF ne = 3 THEN a$ = "Syntax error - too many parameters (Expected _MEMGET mem-reference, offset, variable)": GOTO errmes
                ELSE
                    IF LEN(e$) = 0 THEN e$ = e2$ ELSE e$ = e$ + sp + e2$
                END IF
            NEXT
            var$ = e$
            IF e$ = "" OR ne <> 2 THEN a$ = "Expected _MEMGET mem-reference, offset, variable": GOTO errmes

            e$ = fixoperationorder$(blk$): IF Error_Happened THEN GOTO errmes
            l$ = SCase$("_MemGet") + sp + tlayout$

            test$ = evaluate(e$, typ): IF Error_Happened THEN GOTO errmes
            IF (typ AND ISUDT) = 0 OR (typ AND UDTMASK) <> 1 THEN a$ = "Expected _MEM type": GOTO errmes
            blkoffs$ = evaluatetotyp(e$, -6)

            '            IF typ AND ISREFERENCE THEN e$ = refer(e$, typ, 0)


            'WriteBufLine MainTxtBuf, blkoffs$ '???

            e$ = fixoperationorder$(offs$): IF Error_Happened THEN GOTO errmes
            l$ = l$ + sp2 + "," + sp + tlayout$
            e$ = evaluatetotyp(e$, OFFSETTYPE - ISPOINTER): IF Error_Happened THEN GOTO errmes
            offs$ = e$
            'WriteBufLine MainTxtBuf, e$ '???

            e$ = fixoperationorder$(var$): IF Error_Happened THEN GOTO errmes
            l$ = l$ + sp2 + "," + sp + tlayout$
            varsize$ = evaluatetotyp(e$, -5): IF Error_Happened THEN GOTO errmes
            varoffs$ = evaluatetotyp(e$, -6): IF Error_Happened THEN GOTO errmes


            'WriteBufLine MainTxtBuf, varoffs$ '???
            'WriteBufLine MainTxtBuf, varsize$ '???

            'what do we do next
            'need to know offset of variable and its size

            'known sizes will be handled by designated command casts, otherwise use memmove
            s = 0
            IF varsize$ = "1" THEN s = 1: st$ = "int8"
            IF varsize$ = "2" THEN s = 2: st$ = "int16"
            IF varsize$ = "4" THEN s = 4: st$ = "int32"
            IF varsize$ = "8" THEN s = 8: st$ = "int64"

            IF CheckingOn = 0 THEN
                'fast version:
                IF s THEN
                    WriteBufLine MainTxtBuf, "*(" + st$ + "*)" + varoffs$ + "=*(" + st$ + "*)(" + offs$ + ");"
                ELSE
                    WriteBufLine MainTxtBuf, "memmove(" + varoffs$ + ",(uint8_t*)" + offs$ + "," + varsize$ + ");"
                END IF
            ELSE
                'safe version:
                WriteBufLine MainTxtBuf, "tmp_long=" + offs$ + ";"
                'is mem block init?
                WriteBufLine MainTxtBuf, "if ( ((mem_block*)(" + blkoffs$ + "))->lock_offset ){"
                'are region and id valid?
                WriteBufLine MainTxtBuf, "if ("
                WriteBufLine MainTxtBuf, "tmp_long < ((mem_block*)(" + blkoffs$ + "))->offset  ||"
                WriteBufLine MainTxtBuf, "(tmp_long+(" + varsize$ + ")) > ( ((mem_block*)(" + blkoffs$ + "))->offset + ((mem_block*)(" + blkoffs$ + "))->size)  ||"
                WriteBufLine MainTxtBuf, "((mem_lock*)((mem_block*)(" + blkoffs$ + "))->lock_offset)->id != ((mem_block*)(" + blkoffs$ + "))->lock_id  ){"
                'diagnose error
                WriteBufLine MainTxtBuf, "if (" + "((mem_lock*)((mem_block*)(" + blkoffs$ + "))->lock_offset)->id != ((mem_block*)(" + blkoffs$ + "))->lock_id" + ") error(308); else error(300);"
                WriteBufLine MainTxtBuf, "}else{"
                IF s THEN
                    WriteBufLine MainTxtBuf, "*(" + st$ + "*)" + varoffs$ + "=*(" + st$ + "*)tmp_long;"
                ELSE
                    WriteBufLine MainTxtBuf, "memmove(" + varoffs$ + ",(void*)tmp_long," + varsize$ + ");"
                END IF
                WriteBufLine MainTxtBuf, "}"
                WriteBufLine MainTxtBuf, "}else error(309);"
            END IF

            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
            GOTO finishedline

        END IF
    END IF




    IF n >= 1 THEN
        IF firstelement$ = "_MEMPUT" THEN
            'get expressions
            typ$ = ""
            e$ = ""
            B = 0
            ne = 0
            FOR i2 = 2 TO n
                e2$ = getelement$(ca$, i2)
                IF e2$ = "(" THEN B = B + 1
                IF e2$ = ")" THEN B = B - 1
                IF (e2$ = "," OR UCASE$(e2$) = "AS") AND B = 0 THEN
                    ne = ne + 1
                    IF ne = 1 THEN blk$ = e$: e$ = ""
                    IF ne = 2 THEN offs$ = e$: e$ = ""
                    IF ne = 3 THEN var$ = e$: e$ = ""
                    IF (UCASE$(e2$) = "AS" AND ne <> 3) OR (ne = 3 AND UCASE$(e2$) <> "AS") OR ne = 4 THEN a$ = "Expected _MEMPUT mem-reference,offset,variable|value[AS type]": GOTO errmes
                ELSE
                    IF LEN(e$) = 0 THEN e$ = e2$ ELSE e$ = e$ + sp + e2$
                END IF
            NEXT
            IF ne < 2 OR e$ = "" THEN a$ = "Expected _MEMPUT mem-reference, offset, variable|value[AS type]": GOTO errmes
            IF ne = 2 THEN var$ = e$ ELSE typ$ = UCASE$(e$)

            e$ = fixoperationorder$(blk$): IF Error_Happened THEN GOTO errmes
            l$ = SCase$("_MemPut") + sp + tlayout$

            test$ = evaluate(e$, typ): IF Error_Happened THEN GOTO errmes
            IF (typ AND ISUDT) = 0 OR (typ AND UDTMASK) <> 1 THEN a$ = "Expected _MEM type": GOTO errmes
            blkoffs$ = evaluatetotyp(e$, -6)

            e$ = fixoperationorder$(offs$): IF Error_Happened THEN GOTO errmes
            l$ = l$ + sp2 + "," + sp + tlayout$
            e$ = evaluatetotyp(e$, OFFSETTYPE - ISPOINTER): IF Error_Happened THEN GOTO errmes
            offs$ = e$

            IF ne = 2 THEN
                e$ = fixoperationorder$(var$): IF Error_Happened THEN GOTO errmes
                l$ = l$ + sp2 + "," + sp + tlayout$

                ' Allow a whole inline TYPE member array (unmarked or _Static) to be used as the source
                ' object for _MEMPUT without changing how ordinary expressions are validated elsewhere.
                udt_allow_bare_array = -1
                test$ = evaluate(e$, t)
                udt_allow_bare_array = 0
                IF Error_Happened THEN GOTO errmes
                IF (t AND ISREFERENCE) = 0 AND (t AND ISSTRING) THEN
                    WriteBufLine MainTxtBuf, "g_tmp_str=" + test$ + ";"
                    varsize$ = "g_tmp_str->len"
                    varoffs$ = "g_tmp_str->chr"
                ELSE
                    varsize$ = evaluatetotyp(e$, -5): IF Error_Happened THEN GOTO errmes
                    varoffs$ = evaluatetotyp(e$, -6): IF Error_Happened THEN GOTO errmes
                END IF

                'known sizes will be handled by designated command casts, otherwise use memmove
                s = 0
                IF varsize$ = "1" THEN s = 1: st$ = "int8"
                IF varsize$ = "2" THEN s = 2: st$ = "int16"
                IF varsize$ = "4" THEN s = 4: st$ = "int32"
                IF varsize$ = "8" THEN s = 8: st$ = "int64"

                IF CheckingOn = 0 THEN
                    'fast version:
                    IF s THEN
                        WriteBufLine MainTxtBuf, "*(" + st$ + "*)(" + offs$ + ")=*(" + st$ + "*)" + varoffs$ + ";"
                    ELSE
                        WriteBufLine MainTxtBuf, "memmove((uint8_t*)" + offs$ + "," + varoffs$ + "," + varsize$ + ");"
                    END IF
                ELSE
                    'safe version:
                    WriteBufLine MainTxtBuf, "tmp_long=" + offs$ + ";"
                    'is mem block init?
                    WriteBufLine MainTxtBuf, "if ( ((mem_block*)(" + blkoffs$ + "))->lock_offset ){"
                    'are region and id valid?
                    WriteBufLine MainTxtBuf, "if ("
                    WriteBufLine MainTxtBuf, "tmp_long < ((mem_block*)(" + blkoffs$ + "))->offset  ||"
                    WriteBufLine MainTxtBuf, "(tmp_long+(" + varsize$ + ")) > ( ((mem_block*)(" + blkoffs$ + "))->offset + ((mem_block*)(" + blkoffs$ + "))->size)  ||"
                    WriteBufLine MainTxtBuf, "((mem_lock*)((mem_block*)(" + blkoffs$ + "))->lock_offset)->id != ((mem_block*)(" + blkoffs$ + "))->lock_id  ){"
                    'diagnose error
                    WriteBufLine MainTxtBuf, "if (" + "((mem_lock*)((mem_block*)(" + blkoffs$ + "))->lock_offset)->id != ((mem_block*)(" + blkoffs$ + "))->lock_id" + ") error(308); else error(300);"
                    WriteBufLine MainTxtBuf, "}else{"
                    IF s THEN
                        WriteBufLine MainTxtBuf, "*(" + st$ + "*)tmp_long=*(" + st$ + "*)" + varoffs$ + ";"
                    ELSE
                        WriteBufLine MainTxtBuf, "memmove((void*)tmp_long," + varoffs$ + "," + varsize$ + ");"
                    END IF
                    WriteBufLine MainTxtBuf, "}"
                    WriteBufLine MainTxtBuf, "}else error(309);"
                END IF

            ELSE

                '... AS type method
                'FUNCTION typname2typ& (t2$)
                'typname2typsize = 0 'the default
                t = typname2typ(typ$)
                IF t = 0 THEN a$ = "Invalid type": GOTO errmes
                IF (t AND ISOFFSETINBITS) <> 0 OR (t AND ISUDT) <> 0 OR (t AND ISSTRING) THEN a$ = "_MEMPUT requires numeric type": GOTO errmes
                IF (t AND ISPOINTER) THEN t = t - ISPOINTER
                'attempt conversion...
                e$ = fixoperationorder$(var$): IF Error_Happened THEN GOTO errmes
                l$ = l$ + sp2 + "," + sp + tlayout$ + sp + SCase$("As") + sp + SCase2$(typ$)
                e$ = evaluatetotyp(e$, t): IF Error_Happened THEN GOTO errmes
                st$ = typ2ctyp$(t, "")
                varsize$ = _TOSTR$((t AND UDTMASK) \ 8)
                IF CheckingOn = 0 THEN
                    'fast version:
                    WriteBufLine MainTxtBuf, "*(" + st$ + "*)(" + offs$ + ")=" + e$ + ";"
                ELSE
                    'safe version:
                    WriteBufLine MainTxtBuf, "tmp_long=" + offs$ + ";"
                    'is mem block init?
                    WriteBufLine MainTxtBuf, "if ( ((mem_block*)(" + blkoffs$ + "))->lock_offset ){"
                    'are region and id valid?
                    WriteBufLine MainTxtBuf, "if ("
                    WriteBufLine MainTxtBuf, "tmp_long < ((mem_block*)(" + blkoffs$ + "))->offset  ||"
                    WriteBufLine MainTxtBuf, "(tmp_long+(" + varsize$ + ")) > ( ((mem_block*)(" + blkoffs$ + "))->offset + ((mem_block*)(" + blkoffs$ + "))->size)  ||"
                    WriteBufLine MainTxtBuf, "((mem_lock*)((mem_block*)(" + blkoffs$ + "))->lock_offset)->id != ((mem_block*)(" + blkoffs$ + "))->lock_id  ){"
                    'diagnose error
                    WriteBufLine MainTxtBuf, "if (" + "((mem_lock*)((mem_block*)(" + blkoffs$ + "))->lock_offset)->id != ((mem_block*)(" + blkoffs$ + "))->lock_id" + ") error(308); else error(300);"
                    WriteBufLine MainTxtBuf, "}else{"
                    WriteBufLine MainTxtBuf, "*(" + st$ + "*)tmp_long=" + e$ + ";"
                    WriteBufLine MainTxtBuf, "}"
                    WriteBufLine MainTxtBuf, "}else error(309);"
                END IF

            END IF

            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
            GOTO finishedline

        END IF
    END IF





    IF n >= 1 THEN
        IF firstelement$ = "_MEMFILL" THEN
            'get expressions
            typ$ = ""
            e$ = ""
            B = 0
            ne = 0
            FOR i2 = 2 TO n
                e2$ = getelement$(ca$, i2)
                IF e2$ = "(" THEN B = B + 1
                IF e2$ = ")" THEN B = B - 1
                IF (e2$ = "," OR UCASE$(e2$) = "AS") AND B = 0 THEN
                    ne = ne + 1
                    IF ne = 1 THEN blk$ = e$: e$ = ""
                    IF ne = 2 THEN offs$ = e$: e$ = ""
                    IF ne = 3 THEN bytes$ = e$: e$ = ""
                    IF ne = 4 THEN var$ = e$: e$ = ""
                    IF (UCASE$(e2$) = "AS" AND ne <> 4) OR (ne = 4 AND UCASE$(e2$) <> "AS") OR ne = 5 THEN a$ = "Expected _MEMFILL mem-reference,offset,bytes,variable|value[AS type]": GOTO errmes
                ELSE
                    IF LEN(e$) = 0 THEN e$ = e2$ ELSE e$ = e$ + sp + e2$
                END IF
            NEXT
            IF ne < 3 OR e$ = "" THEN a$ = "Expected _MEMFILL mem-reference, offset, bytes, variable|value[AS type]": GOTO errmes
            IF ne = 3 THEN var$ = e$ ELSE typ$ = UCASE$(e$)

            e$ = fixoperationorder$(blk$): IF Error_Happened THEN GOTO errmes
            l$ = SCase$("_MemFill") + sp + tlayout$

            test$ = evaluate(e$, typ): IF Error_Happened THEN GOTO errmes
            IF (typ AND ISUDT) = 0 OR (typ AND UDTMASK) <> 1 THEN a$ = "Expected " + "_MEM type": GOTO errmes
            blkoffs$ = evaluatetotyp(e$, -6)

            e$ = fixoperationorder$(offs$): IF Error_Happened THEN GOTO errmes
            l$ = l$ + sp2 + "," + sp + tlayout$
            e$ = evaluatetotyp(e$, OFFSETTYPE - ISPOINTER): IF Error_Happened THEN GOTO errmes
            offs$ = e$

            e$ = fixoperationorder$(bytes$): IF Error_Happened THEN GOTO errmes
            l$ = l$ + sp2 + "," + sp + tlayout$
            e$ = evaluatetotyp(e$, OFFSETTYPE - ISPOINTER): IF Error_Happened THEN GOTO errmes
            bytes$ = e$

            IF ne = 3 THEN 'no AS
                e$ = fixoperationorder$(var$): IF Error_Happened THEN GOTO errmes
                l$ = l$ + sp2 + "," + sp + tlayout$
                ' _MEMFILL can also replicate the bytes of a whole inline TYPE member array (unmarked or _Static).
                ' Temporarily enable the bare member-array form only for this evaluation step.
                udt_allow_bare_array = -1
                test$ = evaluate(e$, t)
                udt_allow_bare_array = 0
                IF Error_Happened THEN GOTO errmes
                IF (t AND ISREFERENCE) = 0 AND (t AND ISSTRING) THEN
                    WriteBufLine MainTxtBuf, "tmp_long=(ptrszint)" + test$ + ";"
                    varsize$ = "((qbs*)tmp_long)->len"
                    varoffs$ = "((qbs*)tmp_long)->chr"
                ELSE
                    varsize$ = evaluatetotyp(e$, -5): IF Error_Happened THEN GOTO errmes
                    varoffs$ = evaluatetotyp(e$, -6): IF Error_Happened THEN GOTO errmes
                END IF

                IF CheckingOn = 0 THEN
                    WriteBufLine MainTxtBuf, "sub__memfill_nochecks(" + offs$ + "," + bytes$ + ",(ptrszint)" + varoffs$ + "," + varsize$ + ");"
                ELSE
                    WriteBufLine MainTxtBuf, "sub__memfill((mem_block*)" + blkoffs$ + "," + offs$ + "," + bytes$ + ",(ptrszint)" + varoffs$ + "," + varsize$ + ");"
                END IF

            ELSE

                '... AS type method
                t = typname2typ(typ$)
                IF t = 0 THEN a$ = "Invalid type": GOTO errmes
                IF (t AND ISOFFSETINBITS) <> 0 OR (t AND ISUDT) <> 0 OR (t AND ISSTRING) THEN a$ = "_MEMFILL requires numeric type": GOTO errmes
                IF (t AND ISPOINTER) THEN t = t - ISPOINTER
                'attempt conversion...
                e$ = fixoperationorder$(var$): IF Error_Happened THEN GOTO errmes
                l$ = l$ + sp2 + "," + sp + tlayout$ + sp + SCase$("As") + sp + SCase2$(typ$)
                e$ = evaluatetotyp(e$, t): IF Error_Happened THEN GOTO errmes

                c$ = "sub__memfill_"
                IF CheckingOn = 0 THEN c$ = "sub__memfill_nochecks_"
                IF t AND ISOFFSET THEN
                    c$ = c$ + "OFFSET"
                ELSE
                    IF t AND ISFLOAT THEN
                        IF (t AND UDTMASK) = 32 THEN c$ = c$ + "SINGLE"
                        IF (t AND UDTMASK) = 64 THEN c$ = c$ + "DOUBLE"
                        IF (t AND UDTMASK) = 256 THEN c$ = c$ + "FLOAT" 'padded variable
                    ELSE
                        c$ = c$ + _TOSTR$((t AND UDTMASK) \ 8)
                    END IF
                END IF
                c$ = c$ + "("
                IF CheckingOn THEN c$ = c$ + "(mem_block*)" + blkoffs$ + ","
                WriteBufLine MainTxtBuf, c$ + offs$ + "," + bytes$ + "," + e$ + ");"
            END IF

            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
            GOTO finishedline

        END IF
    END IF













    'note: ABSOLUTE cannot be used without CALL
    cispecial = 0
    IF n > 1 THEN
        IF firstelement$ = "INTERRUPT" OR firstelement$ = "INTERRUPTX" THEN
            a$ = "CALL" + sp + firstelement$ + sp + "(" + sp + getelements$(a$, 2, n) + sp + ")"
            ca$ = "CALL" + sp + firstelement$ + sp + "(" + sp + getelements$(ca$, 2, n) + sp + ")"
            n = n + 3
            firstelement$ = "CALL"
            cispecial = 1
            'fall through
        END IF
    END IF

    usecall = 0
    IF firstelement$ = "CALL" THEN
        usecall = 1
        IF n = 1 THEN a$ = "Expected CALL sub-name [(...)]": GOTO errmes
        cn$ = getelement$(ca$, 2): n$ = UCASE$(cn$)

        IF n > 2 THEN

            IF n <= 4 THEN a$ = "Expected CALL sub-name (...)": GOTO errmes
            IF getelement$(a$, 3) <> "(" OR getelement$(a$, n) <> ")" THEN a$ = "Expected CALL sub-name (...)": GOTO errmes
            a$ = n$ + sp + getelements$(a$, 4, n - 1)
            ca$ = cn$ + sp + getelements$(ca$, 4, n - 1)


            IF n$ = "INTERRUPT" OR n$ = "INTERRUPTX" THEN 'assume CALL INTERRUPT[X] request
                'print "CI: call interrupt command reached":sleep 1
                IF n$ = "INTERRUPT" THEN WriteBufRawData MainTxtBuf, "call_interrupt(" ELSE WriteBufRawData MainTxtBuf, "call_interruptx("
                argn = 0
                n = numelements(a$)
                B = 0
                e$ = ""
                FOR i = 2 TO n
                    e2$ = getelement$(ca$, i)
                    IF e2$ = "(" THEN B = B + 1
                    IF e2$ = ")" THEN B = B - 1
                    IF (e2$ = "," AND B = 0) OR i = n THEN
                        IF i = n THEN
                            IF e$ = "" THEN e$ = e2$ ELSE e$ = e$ + sp + e2$
                        END IF
                        argn = argn + 1
                        IF argn = 1 THEN 'interrupt number
                            e$ = fixoperationorder$(e$)
                            IF Error_Happened THEN GOTO errmes
                            l$ = SCase$("Call") + sp + n$ + sp2 + "(" + sp2 + tlayout$
                            IF cispecial = 1 THEN l$ = n$ + sp + tlayout$
                            e$ = evaluatetotyp(e$, 64&)
                            IF Error_Happened THEN GOTO errmes
                            'print "CI: evaluated interrupt number as ["+e$+"]":sleep 1
                            WriteBufRawData MainTxtBuf, e$
                        END IF
                        IF argn = 2 OR argn = 3 THEN 'inregs, outregs
                            e$ = fixoperationorder$(e$)
                            IF Error_Happened THEN GOTO errmes
                            l$ = l$ + sp2 + "," + sp + tlayout$
                            e2$ = e$
                            e$ = evaluatetotyp(e$, -2) 'offset+size
                            IF Error_Happened THEN GOTO errmes
                            'print "CI: evaluated in/out regs ["+e2$+"] as ["+e$+"]":sleep 1
                            WriteBufRawData MainTxtBuf, "," + e$
                        END IF
                        e$ = ""
                    ELSE
                        IF e$ = "" THEN e$ = e2$ ELSE e$ = e$ + sp + e2$
                    END IF
                NEXT
                IF argn <> 3 THEN a$ = "Expected CALL INTERRUPT (interrupt-no, inregs, outregs)": GOTO errmes
                WriteBufLine MainTxtBuf, ");"
                IF cispecial = 0 THEN l$ = l$ + sp2 + ")"
                layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                'print "CI: done":sleep 1
                GOTO finishedline
            END IF 'call interrupt








            'call to CALL ABSOLUTE beyond reasonable doubt
            IF n$ = "ABSOLUTE" THEN
                l$ = SCase$("Call" + sp + "Absolute" + sp2 + "(" + sp2)
                argn = 0
                n = numelements(a$)
                B = 0
                e$ = ""
                FOR i = 2 TO n
                    e2$ = getelement$(ca$, i)
                    IF e2$ = "(" THEN B = B + 1
                    IF e2$ = ")" THEN B = B - 1
                    IF (e2$ = "," AND B = 0) OR i = n THEN
                        IF i < n THEN
                            IF e$ = "" THEN a$ = "Expected expression before , or )": GOTO errmes
                            '1. variable or value?
                            e$ = fixoperationorder$(e$)
                            IF Error_Happened THEN GOTO errmes
                            l$ = l$ + tlayout$ + sp2 + "," + sp
                            ignore$ = evaluate(e$, typ)
                            IF Error_Happened THEN GOTO errmes

                            IF (typ AND ISPOINTER) <> 0 AND (typ AND ISREFERENCE) <> 0 THEN

                                'assume standard variable
                                'assume not string/array/udt/etc
                                e$ = "VARPTR" + sp + "(" + sp + e$ + sp + ")"
                                e$ = evaluatetotyp(e$, UINTEGERTYPE - ISPOINTER)
                                IF Error_Happened THEN GOTO errmes

                            ELSE

                                'assume not string
                                'single, double or integer64?
                                IF typ AND ISFLOAT THEN
                                    IF (typ AND UDTMASK) = 32 THEN
                                        e$ = evaluatetotyp(e$, SINGLETYPE - ISPOINTER)
                                        IF Error_Happened THEN GOTO errmes
                                        v$ = "pass" + _TOSTR$(uniquenumber)
                                        WriteBufLine defdatahandle, "float *" + v$ + "=NULL;"
                                        WriteBufLine DataTxtBuf, "if(" + v$ + "==NULL){"
                                        WriteBufLine DataTxtBuf, "cmem_sp-=4;"
                                        WriteBufLine DataTxtBuf, v$ + "=(float*)(dblock+cmem_sp);"
                                        WriteBufLine DataTxtBuf, "if (cmem_sp<qbs_cmem_sp) error(257);"
                                        WriteBufLine DataTxtBuf, "}"
                                        e$ = "(uint16)(((uint8*)&(*" + v$ + "=" + e$ + "))-((uint8*)dblock))"
                                    ELSE
                                        e$ = evaluatetotyp(e$, DOUBLETYPE - ISPOINTER)
                                        IF Error_Happened THEN GOTO errmes
                                        v$ = "pass" + _TOSTR$(uniquenumber)
                                        WriteBufLine defdatahandle, "double *" + v$ + "=NULL;"
                                        WriteBufLine DataTxtBuf, "if(" + v$ + "==NULL){"
                                        WriteBufLine DataTxtBuf, "cmem_sp-=8;"
                                        WriteBufLine DataTxtBuf, v$ + "=(double*)(dblock+cmem_sp);"
                                        WriteBufLine DataTxtBuf, "if (cmem_sp<qbs_cmem_sp) error(257);"
                                        WriteBufLine DataTxtBuf, "}"
                                        e$ = "(uint16)(((uint8*)&(*" + v$ + "=" + e$ + "))-((uint8*)dblock))"
                                    END IF
                                ELSE
                                    e$ = evaluatetotyp(e$, INTEGER64TYPE - ISPOINTER)
                                    IF Error_Happened THEN GOTO errmes
                                    v$ = "pass" + _TOSTR$(uniquenumber)
                                    WriteBufLine defdatahandle, "int64 *" + v$ + "=NULL;"
                                    WriteBufLine DataTxtBuf, "if(" + v$ + "==NULL){"
                                    WriteBufLine DataTxtBuf, "cmem_sp-=8;"
                                    WriteBufLine DataTxtBuf, v$ + "=(int64*)(dblock+cmem_sp);"
                                    WriteBufLine DataTxtBuf, "if (cmem_sp<qbs_cmem_sp) error(257);"
                                    WriteBufLine DataTxtBuf, "}"
                                    e$ = "(uint16)(((uint8*)&(*" + v$ + "=" + e$ + "))-((uint8*)dblock))"
                                END IF

                            END IF

                            WriteBufLine MainTxtBuf, "call_absolute_offsets[" + _TOSTR$(argn) + "]=" + e$ + ";"
                        ELSE
                            IF e$ = "" THEN e$ = e2$ ELSE e$ = e$ + sp + e2$
                            e$ = fixoperationorder(e$)
                            IF Error_Happened THEN GOTO errmes
                            l$ = l$ + tlayout$ + sp2 + ")"
                            e$ = evaluatetotyp(e$, UINTEGERTYPE - ISPOINTER)
                            IF Error_Happened THEN GOTO errmes
                            WriteBufLine MainTxtBuf, "call_absolute(" + _TOSTR$(argn) + "," + e$ + ");"
                        END IF
                        argn = argn + 1
                        e$ = ""
                    ELSE
                        IF e$ = "" THEN e$ = e2$ ELSE e$ = e$ + sp + e2$
                    END IF
                NEXT
                layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                GOTO finishedline
            END IF

        ELSE 'n>2

            a$ = n$
            ca$ = cn$
            usecall = 2

        END IF 'n>2

        n = numelements(a$)
        firstelement$ = getelement$(a$, 1)

        'valid SUB name
        validsub = 0
        findidsecondarg = "": IF n >= 2 THEN findidsecondarg = getelement$(a$, 2)
        try = findid(firstelement$)
        IF Error_Happened THEN GOTO errmes
        DO WHILE try
            IF id.subfunc = 2 THEN validsub = 1: EXIT DO
            IF try = 2 THEN
                findidsecondarg = "": IF n >= 2 THEN findidsecondarg = getelement$(a$, 2)
                findanotherid = 1
                try = findid(firstelement$)
                IF Error_Happened THEN GOTO errmes
            ELSE
                try = 0
            END IF
        LOOP
        IF validsub = 0 THEN a$ = "Expected CALL sub-name [(...)]": GOTO errmes
    END IF

    'sub?
    IF n >= 1 THEN

        IF firstelement$ = "?" THEN firstelement$ = "PRINT"

        findidsecondarg = "": IF n >= 2 THEN findidsecondarg = getelement$(a$, 2)
        try = findid(firstelement$)
        IF Error_Happened THEN GOTO errmes
        DO WHILE try
            IF id.subfunc = 2 THEN

                'Keep the SUB origin before any helper can change the current id record.
                subIsInternal = ids(currentid).internal_subfunc

                'check symbol
                s$ = removesymbol$(firstelement$ + "")
                IF Error_Happened THEN GOTO errmes
                IF ASC(id.musthave) = 36 THEN '="$"
                    IF s$ <> "$" THEN GOTO notsubcall 'missing musthave "$"
                ELSE
                    IF LEN(s$) THEN GOTO notsubcall 'unrequired symbol added
                END IF
                'check for variable assignment
                IF n > 1 THEN
                    IF ASC(id.specialformat) <> 61 THEN '<>"="
                        IF ASC(getelement$(a$, 2)) = 61 THEN GOTO notsubcall 'assignment, not sub call
                    END IF
                END IF
                'check for array assignment
                'Only internal SUBs can legally share a name with a variable/array
                '(for example WIDTH). A user-defined SUB name cannot, so do not
                'reinterpret its parenthesized first argument as an array assignment.
                IF subIsInternal THEN
                    IF n > 2 THEN
                        IF firstelement$ <> "PRINT" AND firstelement$ <> "LPRINT" THEN
                            IF getelement$(a$, 2) = "(" THEN
                                B = 1
                                FOR i = 3 TO n
                                    e$ = getelement$(a$, i)
                                    IF e$ = "(" THEN B = B + 1
                                    IF e$ = ")" THEN
                                        B = B - 1
                                        IF B = 0 THEN
                                            IF i = n THEN EXIT FOR
                                            IF getelement$(a$, i + 1) = "=" THEN GOTO notsubcall
                                        END IF
                                    END IF
                                NEXT
                            END IF
                        END IF
                    END IF
                END IF


                'generate error on driect _GL call
                IF firstelement$ = "_GL" THEN
                    a$ = "Cannot call SUB _GL directly": GOTO errmes
                END IF

                IF firstelement$ = "VWATCH" THEN
                    a$ = "Cannot call SUB VWATCH directly": GOTO errmes
                END IF

                IF firstelement$ = "OPEN" THEN
                    'gwbasic or qbasic version?
                    B = 0
                    FOR x = 2 TO n
                        a2$ = getelement$(a$, x)
                        IF a2$ = "(" THEN B = B + 1
                        IF a2$ = ")" THEN B = B - 1
                        IF a2$ = "FOR" OR a2$ = "AS" THEN EXIT FOR 'qb style open verified
                        IF B = 0 AND a2$ = "," THEN 'the gwbasic version includes a comma after the first string expression
                            findanotherid = 1
                            try = findid(firstelement$) 'id of sub_open_gwbasic
                            IF Error_Happened THEN GOTO errmes
                            EXIT FOR
                        END IF
                    NEXT
                END IF


                'IF findid(firstelement$) THEN
                'IF id.subfunc = 2 THEN


                IF firstelement$ = "CLOSE" OR firstelement$ = "RESET" THEN
                    IF firstelement$ = "RESET" THEN
                        IF n > 1 THEN a$ = "Syntax error - RESET takes no parameters": GOTO errmes
                        l$ = SCase$("Reset")
                    ELSE
                        l$ = SCase$("Close")
                    END IF

                    IF n = 1 THEN
                        WriteBufLine MainTxtBuf, "sub_close(NULL,0);" 'closes all files
                    ELSE
                        l$ = l$ + sp
                        B = 0
                        s = 0
                        a3$ = ""
                        FOR x = 2 TO n
                            a2$ = getelement$(ca$, x)
                            IF a2$ = "(" THEN B = B + 1
                            IF a2$ = ")" THEN B = B - 1
                            IF a2$ = "#" AND B = 0 THEN
                                IF s = 0 THEN s = 1 ELSE a$ = "Unexpected #": GOTO errmes
                                l$ = l$ + "#" + sp2
                                GOTO closenexta
                            END IF

                            IF a2$ = "," AND B = 0 THEN
                                IF s = 2 THEN
                                    e$ = fixoperationorder$(a3$)
                                    IF Error_Happened THEN GOTO errmes
                                    l$ = l$ + tlayout$ + sp2 + "," + sp
                                    e$ = evaluatetotyp(e$, 64&)
                                    IF Error_Happened THEN GOTO errmes
                                    WriteBufLine MainTxtBuf, "sub_close(" + e$ + ",1);"
                                    a3$ = ""
                                    s = 0
                                    GOTO closenexta
                                ELSE
                                    a$ = "Expected expression before ,": GOTO errmes
                                END IF
                            END IF

                            s = 2
                            IF a3$ = "" THEN a3$ = a2$ ELSE a3$ = a3$ + sp + a2$

                            closenexta:
                        NEXT

                        IF s = 2 THEN
                            e$ = fixoperationorder$(a3$)
                            IF Error_Happened THEN GOTO errmes
                            l$ = l$ + tlayout$
                            e$ = evaluatetotyp(e$, 64&)
                            IF Error_Happened THEN GOTO errmes
                            WriteBufLine MainTxtBuf, "sub_close(" + e$ + ",1);"
                        ELSE
                            l$ = LEFT$(l$, LEN(l$) - 1)
                        END IF

                    END IF
                    layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                    GOTO finishedline
                END IF 'close
















                'data, restore, read
                IF firstelement$ = "READ" THEN 'file input
                    xread ca$, n
                    IF Error_Happened THEN GOTO errmes
                    'note: layout done in xread sub
                    GOTO finishedline
                END IF 'read





































                lineinput = 0
                IF n >= 2 THEN
                    IF firstelement$ = "LINE" AND secondelement$ = "INPUT" THEN
                        lineinput = 1
                        a$ = RIGHT$(a$, LEN(a$) - 5): ca$ = RIGHT$(ca$, LEN(ca$) - 5): n = n - 1 'remove "LINE"
                        firstelement$ = "INPUT"
                    END IF
                END IF

                IF firstelement$ = "INPUT" THEN 'file input
                    IF n > 1 THEN
                        IF getelement$(a$, 2) = "#" THEN
                            l$ = SCase$("Input") + sp + "#": IF lineinput THEN l$ = SCase$("Line") + sp + l$

                            u$ = _TOSTR$(uniquenumber)
                            'which file?
                            IF n = 2 THEN a$ = "Expected # ... , ...": GOTO errmes
                            a3$ = ""
                            B = 0
                            FOR i = 3 TO n
                                a2$ = getelement$(ca$, i)
                                IF a2$ = "(" THEN B = B + 1
                                IF a2$ = ")" THEN B = B - 1
                                IF a2$ = "," AND B = 0 THEN
                                    IF a3$ = "" THEN a$ = "Expected # ... , ...": GOTO errmes
                                    GOTO inputgotfn
                                END IF
                                IF a3$ = "" THEN a3$ = a2$ ELSE a3$ = a3$ + sp + a2$
                            NEXT
                            inputgotfn:
                            e$ = fixoperationorder$(a3$)
                            IF Error_Happened THEN GOTO errmes
                            l$ = l$ + sp2 + tlayout$
                            e$ = evaluatetotyp(e$, 64&)
                            IF Error_Happened THEN GOTO errmes
                            WriteBufLine MainTxtBuf, "tmp_fileno=" + e$ + ";"
                            WriteBufLine MainTxtBuf, "if (is_error_pending()) goto skip" + u$ + ";"
                            i = i + 1
                            IF i > n THEN a$ = "Expected , ...": GOTO errmes
                            a3$ = ""
                            B = 0
                            FOR i = i TO n
                                a2$ = getelement$(ca$, i)
                                IF a2$ = "(" THEN B = B + 1
                                IF a2$ = ")" THEN B = B - 1
                                IF i = n THEN
                                    IF a3$ = "" THEN a3$ = a2$ ELSE a3$ = a3$ + sp + a2$
                                    a2$ = ",": B = 0
                                END IF
                                IF a2$ = "," AND B = 0 THEN
                                    IF a3$ = "" THEN a$ = "Expected , ...": GOTO errmes
                                    e$ = fixoperationorder$(a3$)
                                    IF Error_Happened THEN GOTO errmes
                                    l$ = l$ + sp2 + "," + sp + tlayout$
                                    e$ = evaluate(e$, t)
                                    IF Error_Happened THEN GOTO errmes
                                    IF (t AND ISREFERENCE) = 0 THEN a$ = "Expected variable-name": GOTO errmes
                                    IF (t AND ISSTRING) THEN
                                        e$ = refer(e$, t, 0)
                                        IF Error_Happened THEN GOTO errmes
                                        IF lineinput THEN
                                            WriteBufLine MainTxtBuf, "sub_file_line_input_string(tmp_fileno," + e$ + ");"
                                            WriteBufLine MainTxtBuf, "if (is_error_pending()) goto skip" + u$ + ";"
                                        ELSE
                                            WriteBufLine MainTxtBuf, "sub_file_input_string(tmp_fileno," + e$ + ");"
                                            WriteBufLine MainTxtBuf, "if (is_error_pending()) goto skip" + u$ + ";"
                                        END IF
                                        stringprocessinghappened = 1
                                    ELSE
                                        IF lineinput THEN a$ = "Expected string-variable": GOTO errmes

                                        'numeric variable
                                        IF (t AND ISFLOAT) <> 0 OR (t AND UDTMASK) <> 64 THEN
                                            IF (t AND ISOFFSETINBITS) THEN
                                                setrefer e$, t, "((int64)func_file_input_float(tmp_fileno," + _TOSTR$(t) + "))", 1
                                                IF Error_Happened THEN GOTO errmes
                                            ELSE
                                                setrefer e$, t, "func_file_input_float(tmp_fileno," + _TOSTR$(t) + ")", 1
                                                IF Error_Happened THEN GOTO errmes
                                            END IF
                                        ELSE
                                            IF t AND ISUNSIGNED THEN
                                                setrefer e$, t, "func_file_input_uint64(tmp_fileno)", 1
                                                IF Error_Happened THEN GOTO errmes
                                            ELSE
                                                setrefer e$, t, "func_file_input_int64(tmp_fileno)", 1
                                                IF Error_Happened THEN GOTO errmes
                                            END IF
                                        END IF

                                        WriteBufLine MainTxtBuf, "if (is_error_pending()) goto skip" + u$ + ";"

                                    END IF
                                    IF i = n THEN EXIT FOR
                                    IF lineinput THEN a$ = "Too many variables": GOTO errmes
                                    a3$ = "": a2$ = ""
                                END IF
                                IF a3$ = "" THEN a3$ = a2$ ELSE a3$ = a3$ + sp + a2$
                            NEXT
                            WriteBufLine MainTxtBuf, "skip" + u$ + ":"
                            IF stringprocessinghappened THEN WriteBufLine MainTxtBuf, cleanupstringprocessingcall$ + "0);"
                            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                            GOTO finishedline
                        END IF
                    END IF
                END IF 'input#


                IF firstelement$ = "INPUT" THEN
                    l$ = SCase$("Input"): IF lineinput THEN l$ = SCase$("Line") + sp + l$
                    commaneeded = 0
                    i = 2

                    newline = 1: IF getelement$(a$, i) = ";" THEN newline = 0: i = i + 1: l$ = l$ + sp + ";"

                    a2$ = getelement$(ca$, i)
                    IF LEFT$(a2$, 1) = CHR$(34) THEN
                        e$ = fixoperationorder$(a2$): l$ = l$ + sp + tlayout$
                        IF Error_Happened THEN GOTO errmes
                        WriteBufLine MainTxtBuf, "qbs_print(qbs_new_txt_len(" + a2$ + "),0);"
                        i = i + 1
                        'MUST be followed by a ; or ,
                        a2$ = getelement$(ca$, i)
                        i = i + 1
                        l$ = l$ + sp2 + a2$
                        IF a2$ = ";" THEN
                            IF lineinput THEN GOTO finishedpromptstring
                            WriteBufLine MainTxtBuf, "qbs_print(qbs_new_txt(" + CHR$(34) + "? " + CHR$(34) + "),0);"
                            GOTO finishedpromptstring
                        END IF
                        IF a2$ = "," THEN
                            GOTO finishedpromptstring
                        END IF
                        a$ = "Syntax error - Reference: INPUT [;] " + CHR$(34) + "[Question or statement text]" + CHR$(34) + "{,|;} variable[, ...] or INPUT ; variable[, ...]": GOTO errmes
                    END IF
                    'there was no promptstring, so print a ?
                    IF lineinput = 0 THEN WriteBufLine MainTxtBuf, "qbs_print(qbs_new_txt(" + CHR$(34) + "? " + CHR$(34) + "),0);"
                    finishedpromptstring:
                    numvar = 0
                    FOR i = i TO n
                        IF commaneeded = 1 THEN
                            a2$ = getelement$(ca$, i)
                            IF a2$ <> "," THEN a$ = "Syntax error - comma expected": GOTO errmes
                        ELSE

                            B = 0
                            e$ = ""
                            FOR i2 = i TO n
                                e2$ = getelement$(ca$, i2)
                                IF e2$ = "(" THEN B = B + 1
                                IF e2$ = ")" THEN B = B - 1
                                IF e2$ = "," AND B = 0 THEN i2 = i2 - 1: EXIT FOR
                                e$ = e$ + sp + e2$
                            NEXT
                            i = i2: IF i > n THEN i = n
                            IF e$ = "" THEN a$ = "Expected variable": GOTO errmes
                            e$ = RIGHT$(e$, LEN(e$) - 1)
                            e$ = fixoperationorder$(e$)
                            IF Error_Happened THEN GOTO errmes
                            l$ = l$ + sp + tlayout$: IF i <> n THEN l$ = l$ + sp2 + ","
                            e$ = evaluate(e$, t)
                            IF Error_Happened THEN GOTO errmes
                            IF (t AND ISREFERENCE) = 0 THEN a$ = "Expected variable": GOTO errmes

                            IF (t AND ISSTRING) THEN
                                e$ = refer(e$, t, 0)
                                IF Error_Happened THEN GOTO errmes
                                numvar = numvar + 1
                                IF lineinput THEN
                                    WriteBufLine MainTxtBuf, "qbs_input_variabletypes[" + _TOSTR$(numvar) + "]=ISSTRING+512;"
                                ELSE
                                    WriteBufLine MainTxtBuf, "qbs_input_variabletypes[" + _TOSTR$(numvar) + "]=ISSTRING;"
                                END IF
                                WriteBufLine MainTxtBuf, "qbs_input_variableoffsets[" + _TOSTR$(numvar) + "]=" + e$ + ";"
                                GOTO gotinputvar
                            END IF

                            IF lineinput THEN a$ = "Expected string variable": GOTO errmes
                            IF (t AND ISARRAY) THEN
                                IF (t AND ISOFFSETINBITS) THEN
                                    a$ = "INPUT cannot handle _BIT array elements": GOTO errmes
                                END IF
                            END IF
                            e$ = "&(" + refer(e$, t, 0) + ")"
                            IF Error_Happened THEN GOTO errmes

                            'remove assumed/unnecessary flags
                            IF (t AND ISPOINTER) THEN t = t - ISPOINTER
                            IF (t AND ISINCONVENTIONALMEMORY) THEN t = t - ISINCONVENTIONALMEMORY
                            IF (t AND ISREFERENCE) THEN t = t - ISREFERENCE

                            'IF (t AND ISOFFSETINBITS) THEN
                            'numvar = numvar + 1
                            'consider storing the bit offset in unused bits of t
                            'WriteBufLine MainTxtBuf, "qbs_input_variabletypes[" + _TOSTR$(numvar) + "]=" + _TOSTR$(t) + ";"
                            'WriteBufLine MainTxtBuf, "qbs_input_variableoffsets[" + _TOSTR$(numvar) + "]=" + refer(ref$, typ, 1) + ";"
                            'GOTO gotinputvar
                            'END IF

                            'assume it is a regular variable
                            numvar = numvar + 1
                            WriteBufLine MainTxtBuf, "qbs_input_variabletypes[" + _TOSTR$(numvar) + "]=" + _TOSTR$(t) + ";"
                            WriteBufLine MainTxtBuf, "qbs_input_variableoffsets[" + _TOSTR$(numvar) + "]=" + e$ + ";"
                            GOTO gotinputvar

                        END IF
                        gotinputvar:
                        commaneeded = commaneeded + 1: IF commaneeded = 2 THEN commaneeded = 0
                    NEXT
                    IF numvar = 0 THEN a$ = "Syntax error - Reference: INPUT [;] " + CHR$(34) + "[Question or statement text]" + CHR$(34) + "{,|;} variable[, ...] or INPUT ; variable[, ...]": GOTO errmes
                    IF lineinput = 1 AND numvar > 1 THEN a$ = "Too many variables": GOTO errmes
                    IF GetRCStateVar(vWatchOn) THEN
                        WriteBufLine MainTxtBuf, "*__LONG_VWATCH_LINENUMBER= -4; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars);"
                    END IF
                    WriteBufLine MainTxtBuf, "qbs_input(" + _TOSTR$(numvar) + "," + _TOSTR$(newline) + ");"
                    WriteBufLine MainTxtBuf, "if (stop_program) end();"
                    IF GetRCStateVar(vWatchOn) THEN
                        WriteBufLine MainTxtBuf, "*__LONG_VWATCH_LINENUMBER= -5; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars);"
                    END IF
                    WriteBufLine MainTxtBuf, cleanupstringprocessingcall$ + "0);"
                    layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                    GOTO finishedline
                END IF



                IF firstelement$ = "WRITE" THEN 'file write
                    IF n > 1 THEN
                        IF getelement$(a$, 2) = "#" THEN
                            xfilewrite ca$, n
                            IF Error_Happened THEN GOTO errmes
                            GOTO finishedline
                        END IF '#
                    END IF 'n>1
                END IF '"write"

                IF firstelement$ = "WRITE" THEN 'write
                    xwrite ca$, n
                    IF Error_Happened THEN GOTO errmes
                    GOTO finishedline
                END IF '"write"

                IF firstelement$ = "PRINT" THEN 'file print
                    IF n > 1 THEN
                        IF getelement$(a$, 2) = "#" THEN
                            xfileprint a$, ca$, n
                            IF Error_Happened THEN GOTO errmes
                            l$ = tlayout$
                            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                            GOTO finishedline
                        END IF '#
                    END IF 'n>1
                END IF '"print"

                IF firstelement$ = "PRINT" OR firstelement$ = "LPRINT" THEN
                    IF secondelement$ <> "USING" THEN 'check to see if we need to auto-add semicolons
                        elementon = 2
                        redosemi:
                        FOR i = elementon TO n - 1
                            nextchar$ = getelement$(a$, i + 1)
                            'Only insert ; if next char cannot continue an expression from a string literal.
                            'The cute pattern is a match for all the less-equal-greater than operators.
                            IF INSTR(";,+)<=>=<>", nextchar$) = 0 THEN
                                temp1$ = getelement$(a$, i)
                                beginpoint = INSTR(beginpoint, temp1$, CHR$(34))
                                endpoint = INSTR(beginpoint + 1, temp1$, CHR$(34) + ",")
                                IF beginpoint <> 0 AND endpoint <> 0 THEN 'if we have both positions
                                    'Quote without semicolon check (like PRINT "abc"123)
                                    textlength = endpoint - beginpoint - 1
                                    textvalue$ = MID$(temp1$, endpoint + 2, LEN(_TOSTR$(textlength)))
                                    IF VAL(textvalue$) = textlength THEN
                                        insertelements a$, i, ";"
                                        insertelements ca$, i, ";"
                                        n = n + 1
                                        elementon = i + 2 'just an easy way to reduce redundant calls to the routine
                                        GOTO redosemi
                                    END IF
                                END IF
                                IF temp1$ <> "USING" THEN
                                    IF LEFT$(LTRIM$(nextchar$), 1) = CHR$(34) THEN
                                        IF INSTR(";,+(<=>=<>", temp1$) = 0 THEN
                                            'Current element can't appear before a string literal in an expression
                                            insertelements a$, i, ";"
                                            insertelements ca$, i, ";"
                                            n = n + 1
                                            elementon = i + 2 'just an easy way to reduce redundant calls to the routine
                                            GOTO redosemi
                                        END IF
                                    END IF
                                END IF
                            END IF
                        NEXT
                    END IF

                    xprint a$, ca$, n
                    IF Error_Happened THEN GOTO errmes
                    l$ = tlayout$
                    layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                    GOTO finishedline
                END IF



                IF firstelement$ = "CLEAR" THEN
                    IF subfunc$ <> "" THEN a$ = "CLEAR cannot be used inside a SUB/FUNCTION": GOTO errmes
                    FOR i2 = 2 TO n
                        a2$ = getelement$(ca$, i2)
                        IF a2$ = "(" OR a2$ = ")" THEN a$ = "Incorrect number of arguments": GOTO errmes
                    NEXT
                END IF

                'LSET/RSET
                IF firstelement$ = "LSET" OR firstelement$ = "RSET" THEN
                    IF n = 1 THEN a$ = "Expected " + firstelement$ + " ...": GOTO errmes
                    IF firstelement$ = "LSET" THEN l$ = SCase$("LSet") ELSE l$ = SCase$("RSet")
                    dest$ = ""
                    source$ = ""
                    part = 1
                    i = 2
                    a3$ = ""
                    B = 0
                    DO
                        IF i > n THEN
                            IF part <> 2 OR a3$ = "" THEN a$ = "Expected LSET/RSET stringvariable=string": GOTO errmes
                            source$ = a3$
                            EXIT DO
                        END IF
                        a2$ = getelement$(ca$, i)
                        IF a2$ = "(" THEN B = B + 1
                        IF a2$ = ")" THEN B = B - 1
                        IF a2$ = "=" AND B = 0 THEN
                            IF part = 1 THEN dest$ = a3$: part = 2: a3$ = "": GOTO lrsetgotpart
                        END IF
                        IF LEN(a3$) THEN a3$ = a3$ + sp + a2$ ELSE a3$ = a2$
                        lrsetgotpart:
                        i = i + 1
                    LOOP
                    IF dest$ = "" THEN a$ = "Expected LSET/RSET stringvariable=string": GOTO errmes
                    'check if it is a valid source string
                    f$ = fixoperationorder$(dest$)
                    IF Error_Happened THEN GOTO errmes
                    l$ = l$ + sp + tlayout$ + sp + "="
                    e$ = evaluate(f$, sourcetyp)
                    IF Error_Happened THEN GOTO errmes
                    IF (sourcetyp AND ISREFERENCE) = 0 OR (sourcetyp AND ISSTRING) = 0 THEN a$ = "LSET/RSET expects a string variable/array-element as its first argument": GOTO errmes
                    dest$ = evaluatetotyp(f$, ISSTRING)
                    IF Error_Happened THEN GOTO errmes
                    source$ = fixoperationorder$(source$)
                    IF Error_Happened THEN GOTO errmes
                    l$ = l$ + sp + tlayout$
                    layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                    source$ = evaluatetotyp(source$, ISSTRING)
                    IF Error_Happened THEN GOTO errmes
                    IF firstelement$ = "LSET" THEN
                        WriteBufLine MainTxtBuf, "sub_lset(" + dest$ + "," + source$ + ");"
                    ELSE
                        WriteBufLine MainTxtBuf, "sub_rset(" + dest$ + "," + source$ + ");"
                    END IF
                    GOTO finishedline
                END IF

                'SWAP
                IF firstelement$ = "SWAP" THEN
                    IF n < 4 THEN a$ = "Expected SWAP ... , ...": GOTO errmes
                    B = 0
                    ele = 1
                    e1$ = ""
                    e2$ = ""
                    FOR i = 2 TO n
                        e$ = getelement$(ca$, i)
                        IF e$ = "(" THEN B = B + 1
                        IF e$ = ")" THEN B = B - 1
                        IF e$ = "," AND B = 0 THEN
                            IF ele = 2 THEN a$ = "Expected SWAP ... , ...": GOTO errmes
                            ele = 2
                        ELSE
                            IF ele = 1 THEN e1$ = e1$ + sp + e$ ELSE e2$ = e2$ + sp + e$
                        END IF
                    NEXT
                    IF e2$ = "" THEN a$ = "Expected SWAP ... , ...": GOTO errmes
                    e1$ = RIGHT$(e1$, LEN(e1$) - 1): e2$ = RIGHT$(e2$, LEN(e2$) - 1)

                    e1$ = fixoperationorder(e1$)
                    IF Error_Happened THEN GOTO errmes
                    e1l$ = tlayout$
                    e2$ = fixoperationorder(e2$)
                    IF Error_Happened THEN GOTO errmes
                    e2l$ = tlayout$
                    e1$ = evaluate(e1$, e1typ): e2$ = evaluate(e2$, e2typ)
                    IF Error_Happened THEN GOTO errmes
                    IF (e1typ AND ISREFERENCE) = 0 OR (e2typ AND ISREFERENCE) = 0 THEN a$ = "Expected variable": GOTO errmes

                    layoutdone = 1
                    l$ = SCase$("Swap") + sp + e1l$ + sp2 + "," + sp + e2l$
                    IF LEN(layout$) = 0 THEN layout$ = l$ ELSE layout$ = layout$ + sp + l$

                    'swap strings?
                    IF (e1typ AND ISSTRING) THEN
                        IF (e2typ AND ISSTRING) = 0 THEN a$ = "Type mismatch": GOTO errmes
                        e1$ = refer(e1$, e1typ, 0): e2$ = refer(e2$, e2typ, 0)
                        IF Error_Happened THEN GOTO errmes
                        WriteBufLine MainTxtBuf, "swap_string(" + e1$ + "," + e2$ + ");"
                        GOTO finishedline
                    END IF

                    'swap UDT?
                    'note: entire UDTs, unlike their elements cannot be swapped like standard variables
                    '      as UDT sizes may vary, and to avoid a malloc operation, QB64 should allocate a buffer
                    '      in global.txt for the purpose of swapping each UDT type

                    IF e1typ AND ISUDT THEN
                        a$ = e1$
                        'retrieve ID
                        i = INSTR(a$, sp3)
                        IF i THEN
                            idnumber = VAL(LEFT$(a$, i - 1)): a$ = RIGHT$(a$, LEN(a$) - i)
                            getid idnumber
                            IF Error_Happened THEN GOTO errmes
                            u = VAL(a$)
                            i = INSTR(a$, sp3): a$ = RIGHT$(a$, LEN(a$) - i): member_element_id = VAL(a$)
                            i = INSTR(a$, sp3): o$ = RIGHT$(a$, LEN(a$) - i)
                            n$ = "UDT_" + RTRIM$(id.n): IF id.t = 0 THEN n$ = "ARRAY_" + n$ + "[0]"
                            lhsdynudt% = id.dynudt
                            lhsdynmode% = id.dynudtmode
                            IF member_element_id = 0 THEN 'not an element of UDT u
                                lhsscope$ = scope$
                                e$ = e2$: t2 = e2typ
                                IF (t2 AND ISUDT) = 0 THEN a$ = "Expected SWAP with similar user defined type": GOTO errmes
                                idnumber2 = VAL(e$)
                                getid idnumber2
                                IF Error_Happened THEN GOTO errmes
                                rhsdynudt% = id.dynudt
                                rhsdynmode% = id.dynudtmode
                                n2$ = "UDT_" + RTRIM$(id.n): IF id.t = 0 THEN n2$ = "ARRAY_" + n2$ + "[0]"
                                i = INSTR(e$, sp3): e$ = RIGHT$(e$, LEN(e$) - i): u2 = VAL(e$)
                                i = INSTR(e$, sp3): e$ = RIGHT$(e$, LEN(e$) - i): e2 = VAL(e$)

                                i = INSTR(e$, sp3): o2$ = RIGHT$(e$, LEN(e$) - i)
                                'WARNING: u2 may need minor modifications based on e to see if they are the same
                                IF u <> u2 OR e2 <> 0 THEN a$ = "Expected SWAP with similar user defined type": GOTO errmes
                                dst$ = "(((char*)" + lhsscope$ + n$ + ")+(" + o$ + "))"
                                src$ = "(((char*)" + scope$ + n2$ + ")+(" + o2$ + "))"
                                IF UDTDynHasMemberArrays%(u, lhsdynmode%) AND (lhsdynudt% OR rhsdynudt%) THEN
                                    IF lhsdynudt% = 0 OR rhsdynudt% = 0 THEN a$ = "Cannot SWAP these TYPE values because their nested-array storage layouts are incompatible": GOTO errmes
                                    IF lhsdynmode% <> rhsdynmode% THEN a$ = "Cannot SWAP these TYPE values because their nested-array storage layouts are incompatible": GOTO errmes
                                    B = UDTDynLayoutSize&(u) \ 8
                                    siz$ = _TOSTR$(B)
                                    WriteBufLine MainTxtBuf, "{"
                                    WriteBufLine MainTxtBuf, "uint8 *dyn_swap_tmp=(uint8*)malloc((size_t)" + siz$ + ");"
                                    WriteBufLine MainTxtBuf, "if (!dyn_swap_tmp) error(257);"
                                    WriteBufLine MainTxtBuf, "memcpy((void*)dyn_swap_tmp,(void*)(" + dst$ + "),(size_t)" + siz$ + ");"
                                    WriteBufLine MainTxtBuf, "memcpy((void*)(" + dst$ + "),(void*)(" + src$ + "),(size_t)" + siz$ + ");"
                                    WriteBufLine MainTxtBuf, "memcpy((void*)(" + src$ + "),(void*)dyn_swap_tmp,(size_t)" + siz$ + ");"
                                    WriteBufLine MainTxtBuf, "free((void*)dyn_swap_tmp);"
                                    WriteBufLine MainTxtBuf, "}"
                                ELSE
                                    B = udtxsize(u) \ 8
                                    siz$ = _TOSTR$(B)
                                    IF B = 1 THEN WriteBufLine MainTxtBuf, "swap_8(" + src$ + "," + dst$ + ");"
                                    IF B = 2 THEN WriteBufLine MainTxtBuf, "swap_16(" + src$ + "," + dst$ + ");"
                                    IF B = 4 THEN WriteBufLine MainTxtBuf, "swap_32(" + src$ + "," + dst$ + ");"
                                    IF B = 8 THEN WriteBufLine MainTxtBuf, "swap_64(" + src$ + "," + dst$ + ");"
                                    IF B <> 1 AND B <> 2 AND B <> 4 AND B <> 8 THEN WriteBufLine MainTxtBuf, "swap_block(" + src$ + "," + dst$ + "," + siz$ + ");"
                                END IF
                                GOTO finishedline
                            END IF 'e=0
                        END IF 'i
                    END IF 'isudt

                    'cull irrelevant flags to make comparison possible
                    e1typc = e1typ
                    IF e1typc AND ISPOINTER THEN e1typc = e1typc - ISPOINTER
                    IF e1typc AND ISINCONVENTIONALMEMORY THEN e1typc = e1typc - ISINCONVENTIONALMEMORY
                    IF e1typc AND ISARRAY THEN e1typc = e1typc - ISARRAY
                    IF e1typc AND ISUNSIGNED THEN e1typc = e1typc - ISUNSIGNED
                    IF e1typc AND ISUDT THEN e1typc = e1typc - ISUDT
                    e2typc = e2typ
                    IF e2typc AND ISPOINTER THEN e2typc = e2typc - ISPOINTER
                    IF e2typc AND ISINCONVENTIONALMEMORY THEN e2typc = e2typc - ISINCONVENTIONALMEMORY
                    IF e2typc AND ISARRAY THEN e2typc = e2typc - ISARRAY
                    IF e2typc AND ISUNSIGNED THEN e2typc = e2typc - ISUNSIGNED
                    IF e2typc AND ISUDT THEN e2typc = e2typc - ISUDT
                    IF e1typc <> e2typc THEN a$ = "Type mismatch": GOTO errmes
                    t = e1typ
                    IF t AND ISOFFSETINBITS THEN a$ = "Cannot SWAP bit-length variables": GOTO errmes
                    B = t AND UDTMASK
                    t$ = _TOSTR$(B): IF B > 64 THEN t$ = "longdouble"
                    WriteBufLine MainTxtBuf, "swap_" + t$ + "(&" + refer(e1$, e1typ, 0) + ",&" + refer(e2$, e2typ, 0) + ");"
                    IF Error_Happened THEN GOTO errmes
                    GOTO finishedline
                END IF

                IF firstelement$ = "OPTION" THEN
                    IF GetRCStateVar(OptExpl) = 0 THEN e$ = " or OPTION _EXPLICIT" ELSE e$ = ""
                    IF GetRCStateVar(OptExplArr) = 0 THEN e$ = e$ + " or OPTION _EXPLICITARRAY"
                    IF n = 1 THEN a$ = "Expected OPTION BASE" + e$: GOTO errmes
                    e$ = getelement$(a$, 2)
                    SELECT CASE e$
                        CASE "BASE"
                            l$ = getelement$(a$, 3)
                            IF l$ <> "0" AND l$ <> "1" THEN a$ = "Expected OPTION BASE 0 or 1": GOTO errmes
                            IF l$ = "1" THEN optionbase = 1 ELSE optionbase = 0
                            l$ = SCase$("Option" + sp + "Base") + sp + l$
                            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                            GOTO finishedline
                        CASE "_EXPLICIT"
                            SetRCStateVar OptExpl, 1
                            l$ = SCase$("Option" + sp + "_Explicit")
                            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                            GOTO finishedline
                        CASE "_EXPLICITARRAY"
                            SetRCStateVar OptExplArr, 1
                            l$ = SCase$("Option" + sp + "_ExplicitArray")
                            layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
                            GOTO finishedline
                        CASE ELSE
                            IF GetRCStateVar(OptExpl) = 0 THEN e$ = " or OPTION _EXPLICIT" ELSE e$ = ""
                            IF GetRCStateVar(OptExplArr) = 0 THEN e$ = e$ + " or OPTION _EXPLICITARRAY"
                            a$ = "Expected OPTION BASE" + e$: GOTO errmes
                    END SELECT
                END IF

                IF firstelement$ = "_LOGTRACE" THEN
                    EmitLoggingStatement getelements$(ca$, 2, n), "TRACE"
                    IF Error_Happened THEN GOTO errmes
                    GOTO finishedline
                END IF

                IF firstelement$ = "_LOGINFO" THEN
                    EmitLoggingStatement getelements$(ca$, 2, n), "INFO"
                    IF Error_Happened THEN GOTO errmes
                    GOTO finishedline
                END IF

                IF firstelement$ = "_LOGWARN" THEN
                    EmitLoggingStatement getelements$(ca$, 2, n), "WARN"
                    IF Error_Happened THEN GOTO errmes
                    GOTO finishedline
                END IF

                IF firstelement$ = "_LOGERROR" THEN
                    EmitLoggingStatement getelements$(ca$, 2, n), "ERROR"
                    IF Error_Happened THEN GOTO errmes
                    GOTO finishedline
                END IF

                'any other "unique" subs can be processed above

                id2 = id

                targetid = currentid

                IF RTRIM$(id2.callname) = "sub_stub" THEN a$ = "Command not implemented": GOTO errmes

                IF n > 1 THEN
                    IF id2.args = 0 THEN a$ = "SUB does not require any arguments": GOTO errmes
                END IF

                SetDependency id2.Dependency

                seperateargs_error = 0
                passedneeded = seperateargs(getelements(a$, 2, n), getelements(ca$, 2, n), passed&)
                IF seperateargs_error THEN a$ = seperateargs_error_message: GOTO errmes

                'backup args to local string array space before calling evaluate
                FOR i = 1 TO OptMax: separgs2(i) = "": NEXT 'save space!
                FOR i = 1 TO OptMax + 1: separgslayout2(i) = "": NEXT
                FOR i = 1 TO id2.args: separgs2(i) = separgs(i): NEXT
                FOR i = 1 TO id2.args + 1: separgslayout2(i) = separgslayout(i): NEXT



                IF Debug THEN
                    PRINT #9, "separgs:": FOR i = 1 TO id2.args: PRINT #9, i, separgs2(i): NEXT
                    PRINT #9, "separgslayout:": FOR i = 1 TO id2.args + 1: PRINT #9, i, separgslayout2(i): NEXT
                END IF



                'note: seperateargs finds the arguments to pass and sets passed& as necessary
                '      FIXOPERTIONORDER is not called on these args yet
                '      what we need it to do is build a second array of layout info at the same time
                '   ref:DIM SHARED separgslayout(100) AS STRING
                '   the above array stores what layout info (if any) goes BEFORE the arg in question
                '       it has one extra index which is the arg after

                IF usecall THEN
                    IF id.internal_subfunc THEN
                        IF usecall = 1 THEN l$ = SCase$("Call") + sp + SCase$(RTRIM$(id.cn)) + RTRIM$(id.musthave) + sp2 + "(" + sp2
                        IF usecall = 2 THEN l$ = SCase$("Call") + sp + SCase$(RTRIM$(id.cn)) + RTRIM$(id.musthave) + sp 'sp at end for easy parsing
                    ELSE
                        IF usecall = 1 THEN l$ = SCase$("Call") + sp + RTRIM$(id.cn) + RTRIM$(id.musthave) + sp2 + "(" + sp2
                        IF usecall = 2 THEN l$ = SCase$("Call") + sp + RTRIM$(id.cn) + RTRIM$(id.musthave) + sp 'sp at end for easy parsing
                    END IF
                ELSE
                    IF id.internal_subfunc THEN
                        l$ = SCase$(RTRIM$(id.cn)) + RTRIM$(id.musthave) + sp
                    ELSE
                        l$ = RTRIM$(id.cn) + RTRIM$(id.musthave) + sp
                    END IF
                END IF

                subcall$ = RTRIM$(id.callname) + "("
                subargprep$ = ""
                addedlayout = 0
                dynfilepost$ = ""

                fieldcall = 0
                'GET/PUT field exception
                IF RTRIM$(id2.callname) = "sub_get" OR RTRIM$(id2.callname) = "sub_put" THEN
                    IF passed AND 2 THEN
                        'regular GET/PUT call with variable provided
                        passed = passed - 2 'for compliance with existing methods, remove 'passed' flag for the passing of a variable
                    ELSE
                        'FIELD GET/PUT call with variable omitted
                        IF RTRIM$(id2.callname) = "sub_get" THEN
                            fieldcall = 1
                            subcall$ = "field_get("
                        ELSE
                            fieldcall = 2
                            subcall$ = "field_put("
                        END IF
                    END IF
                END IF 'field exception

                IF RTRIM$(id2.callname) = "sub_timer" OR RTRIM$(id2.callname) = "sub_key" THEN 'spacing exception
                    IF usecall = 0 THEN
                        l$ = LEFT$(l$, LEN(l$) - 1) + sp2
                    END IF
                END IF

                FOR i = 1 TO id2.args
                    targettyp = CVL(MID$(id2.arg, -3 + i * 4, 4))
                    nele = ASC(MID$(id2.nele, i, 1))
                    nelereq = ASC(MID$(id2.nelereq, i, 1))

                    addlayout = 1 'omits option values in layout (eg. BINARY="2")
                    convertspacing = 0 'if an 'equation' is next, it will be preceded by a space
                    x$ = separgslayout2$(i)
                    DO WHILE LEN(x$)
                        x = ASC(x$)
                        IF x THEN
                            convertspacing = 0
                            x2$ = MID$(x$, 2, x)
                            x$ = RIGHT$(x$, LEN(x$) - x - 1)

                            s = 0
                            an = 0
                            x3$ = RIGHT$(l$, 1)
                            IF x3$ = sp THEN s = 1
                            IF x3$ = sp2 THEN
                                s = 2
                                IF alphanumeric(ASC(RIGHT$(l$, 2))) THEN an = 1
                            ELSE
                                IF alphanumeric(ASC(x3$)) THEN an = 1
                            END IF
                            s1 = s

                            IF alphanumeric(ASC(x2$)) THEN convertspacing = 1


                            IF x2$ = "LPRINT" THEN

                                'x2$="LPRINT"
                                'x$=CHR$(0)
                                'x3$=[sp] from WIDTH[sp]
                                'therefore...
                                's=1
                                'an=0
                                'convertspacing=1


                                'if debug=1 then
                                'print #9,"LPRINT:"
                                'print #9,s
                                'print #9,an
                                'print #9,l$
                                'print #9,x2$
                                'end if

                            END IF




                            IF (an = 1 OR addedlayout = 1) AND alphanumeric(ASC(x2$)) <> 0 THEN



                                s = 1 'force space
                                x2$ = x2$ + sp2
                                GOTO customlaychar
                            END IF

                            IF x2$ = "=" THEN
                                s = 1
                                x2$ = x2$ + sp
                                GOTO customlaychar
                            END IF

                            IF x2$ = "#" THEN
                                s = 1
                                x2$ = x2$ + sp2
                                GOTO customlaychar
                            END IF

                            IF x2$ = "," THEN x2$ = x2$ + sp: GOTO customlaychar


                            IF x$ = CHR$(0) THEN 'substitution
                                IF x2$ = "STEP" THEN x2$ = x2$ + sp2: GOTO customlaychar
                                x2$ = x2$ + sp: GOTO customlaychar
                            END IF

                            'default solution sp2+?+sp2
                            x2$ = x2$ + sp2





                            customlaychar:
                            IF s = 0 THEN s = 2
                            IF s <> s1 THEN
                                IF s1 THEN l$ = LEFT$(l$, LEN(l$) - 1)
                                IF s = 1 THEN l$ = l$ + sp
                                IF s = 2 THEN l$ = l$ + sp2
                            END IF

                            IF (RTRIM$(id2.callname) = "sub_timer" OR RTRIM$(id2.callname) = "sub_key") AND i = id2.args THEN 'spacing exception
                                IF x2$ <> ")" + sp2 THEN
                                    l$ = LEFT$(l$, LEN(l$) - 1) + sp
                                END IF
                            END IF

                            l$ = l$ + x2$

                        ELSE
                            addlayout = 0
                            x$ = RIGHT$(x$, LEN(x$) - 1)
                        END IF
                        addedlayout = 0
                    LOOP



                    '---better sub syntax checking begins here---



                    IF targettyp = -3 THEN
                        IF separgs2(i) = "N-LL" THEN a$ = "Expected array name": GOTO errmes
                        'names of numeric arrays have ( ) automatically appended (nothing else)
                        e$ = separgs2(i)

                        IF INSTR(e$, sp) = 0 THEN 'one element only
                            try_string$ = e$
                            try = findid(try_string$)
                            IF Error_Happened THEN GOTO errmes
                            DO
                                IF try THEN
                                    IF id.arraytype THEN
                                        IF (id.arraytype AND ISSTRING) = 0 THEN
                                            e$ = e$ + sp + "(" + sp + ")"
                                            EXIT DO
                                        END IF
                                    END IF
                                    '---
                                    IF try = 2 THEN findanotherid = 1: try = findid(try_string$) ELSE try = 0
                                    IF Error_Happened THEN GOTO errmes
                                END IF 'if try
                                IF try = 0 THEN 'add symbol?
                                    IF LEN(removesymbol$(try_string$)) = 0 THEN
                                        IF Error_Happened THEN GOTO errmes
                                        a = ASC(try_string$)
                                        IF a >= 97 AND a <= 122 THEN a = a - 32
                                        IF a = 95 THEN a = 91
                                        a = a - 64
                                        IF LEN(defineextaz(a)) THEN try_string$ = try_string$ + defineextaz(a): try = findid(try_string$)
                                        IF Error_Happened THEN GOTO errmes
                                    END IF
                                END IF 'try=0
                            LOOP UNTIL try = 0
                        END IF 'one element only



                        e$ = fixoperationorder$(e$)
                        IF Error_Happened THEN GOTO errmes
                        IF convertspacing = 1 AND addlayout = 1 THEN l$ = LEFT$(l$, LEN(l$) - 1) + sp
                        IF addlayout THEN l$ = l$ + tlayout$: addedlayout = 1



                        ' Special handling: _WAVE
                        IF firstelement$ = "_WAVE" THEN
                            e2$ = e$ 'backup

                            e$ = evaluate(e$, sourcetyp)
                            IF Error_Happened THEN GOTO errmes

                            ' It must be an array
                            IF (sourcetyp AND ISREFERENCE) = 0 OR (sourcetyp AND ISARRAY) = 0 THEN
                                a$ = "Expected _BYTE array name": GOTO errmes
                            END IF

                            ' Only _BYTE array is allowed
                            IF (sourcetyp AND ISSTRING) OR (sourcetyp AND ISFLOAT) OR (sourcetyp AND ISOFFSET) OR (sourcetyp AND ISUDT) OR (sourcetyp AND ISUNSIGNED) OR (sourcetyp AND UDTMASK) <> 8 THEN
                                a$ = "Expected _BYTE array name": GOTO errmes
                            END IF

                            e$ = e2$ 'restore
                        END IF

                        ' Special handling: _SNDRAWBATCH
                        IF firstelement$ = "_SNDRAWBATCH" THEN
                            e2$ = e$ 'backup

                            e$ = evaluate(e$, sourcetyp)
                            IF Error_Happened THEN GOTO errmes

                            ' It must be an array
                            IF (sourcetyp AND ISREFERENCE) = 0 OR (sourcetyp AND ISARRAY) = 0 THEN
                                a$ = "Expected SINGLE array name": GOTO errmes
                            END IF

                            ' Only 32-bit floating-point array is allowed
                            IF (sourcetyp AND ISFLOAT) = 0 OR (sourcetyp AND UDTMASK) <> 32 THEN
                                a$ = "Expected SINGLE array name": GOTO errmes
                            END IF

                            e$ = e2$ 'restore
                        END IF



                        e$ = evaluatetotyp(e$, -2)
                        IF Error_Happened THEN GOTO errmes
                        GOTO sete
                    END IF '-3


                    IF targettyp = -2 THEN
                        e$ = fixoperationorder$(e$)
                        IF Error_Happened THEN GOTO errmes
                        IF convertspacing = 1 AND addlayout = 1 THEN l$ = LEFT$(l$, LEN(l$) - 1) + sp
                        IF addlayout THEN l$ = l$ + tlayout$: addedlayout = 1
                        e$ = evaluatetotyp(e$, -2)
                        IF Error_Happened THEN GOTO errmes
                        GOTO sete
                    END IF '-2

                    IF targettyp = -4 THEN

                        IF fieldcall THEN
                            i = id2.args + 1
                            EXIT FOR
                        END IF

                        IF separgs2(i) = "N-LL" THEN a$ = "Expected variable name/array element": GOTO errmes
                        e$ = fixoperationorder$(separgs2(i))
                        IF Error_Happened THEN GOTO errmes
                        IF convertspacing = 1 AND addlayout = 1 THEN l$ = LEFT$(l$, LEN(l$) - 1) + sp
                        IF addlayout THEN l$ = l$ + tlayout$: addedlayout = 1

                        'GET/PUT RANDOM-ACCESS override
                        IF firstelement$ = "GET" OR firstelement$ = "PUT" THEN
                            e2$ = e$ 'backup

                            'Whole UDT array references like dynArr() are normally evaluated via
                            'the UDT-reference path, not as the raw arrayreference id|0 token.
                            'Detect that simple source form before evaluate(), otherwise GET/PUT
                            'falls back to the physical descriptor layout and corrupts _Dynamic
                            'descriptors by reading/writing descriptor bytes directly.
                            dynfilearr$ = WholeArrayName$(e$)
                            IF dynfilearr$ <> "" THEN
                                try = findid(dynfilearr$)
                                IF Error_Happened THEN GOTO errmes
                                DO WHILE try
                                    IF id.arraytype AND ISUDT THEN
                                        IF id.dynudt THEN
                                            udt = id.arraytype AND UDTMASK
                                            IF UDTDynHasMemberArrays%(udt, id.dynudtmode) THEN
                                                IF firstelement$ = "GET" THEN
                                                    e$ = UDTFileArrayBE$(RTRIM$(id.callname), udt, id.dynudtmode, id.arrayelements, -1, dynfilepost$)
                                                ELSE
                                                    e$ = UDTFileArrayBE$(RTRIM$(id.callname), udt, id.dynudtmode, id.arrayelements, 0, dynfilepost$)
                                                END IF
                                                IF Error_Happened THEN GOTO errmes
                                                GOTO sete
                                            END IF
                                        END IF
                                    END IF
                                    IF try = 2 THEN findanotherid = 1: try = findid(dynfilearr$) ELSE try = 0
                                    IF Error_Happened THEN GOTO errmes
                                LOOP
                            END IF

                            e$ = evaluate(e$, sourcetyp)
                            IF Error_Happened THEN GOTO errmes
                            IF (sourcetyp AND ISARRAY) AND (sourcetyp AND ISUDT) THEN
                                IF RIGHT$(e$, 2) = sp3 + "0" THEN
                                    idnumber = VAL(LEFT$(e$, INSTR(e$, sp3) - 1))
                                    getid idnumber
                                    IF Error_Happened THEN GOTO errmes
                                    IF id.dynudt THEN
                                        udt = id.arraytype AND UDTMASK
                                        IF UDTDynHasMemberArrays%(udt, id.dynudtmode) THEN
                                            IF firstelement$ = "GET" THEN
                                                e$ = UDTFileArrayBE$(RTRIM$(id.callname), udt, id.dynudtmode, id.arrayelements, -1, dynfilepost$)
                                            ELSE
                                                e$ = UDTFileArrayBE$(RTRIM$(id.callname), udt, id.dynudtmode, id.arrayelements, 0, dynfilepost$)
                                            END IF
                                            IF Error_Happened THEN GOTO errmes
                                            GOTO sete
                                        END IF
                                    END IF
                                END IF
                            END IF
                            IF (sourcetyp AND ISSTRING) THEN
                                IF (sourcetyp AND ISFIXEDLENGTH) = 0 THEN
                                    'replace name of sub to call
                                    subcall$ = RIGHT$(subcall$, LEN(subcall$) - 7) 'delete original name
                                    'note: GET2 & PUT2 take differing input, following code is correct
                                    IF firstelement$ = "GET" THEN
                                        subcall$ = "sub_get2" + subcall$
                                        e$ = refer(e$, sourcetyp, 0) 'pass a qbs pointer instead
                                        IF Error_Happened THEN GOTO errmes
                                        GOTO sete
                                    ELSE
                                        subcall$ = "sub_put2" + subcall$
                                        'no goto sete required, fall through
                                    END IF
                                END IF
                            END IF
                            e$ = e2$ 'restore
                        END IF 'override

                        e$ = evaluatetotyp(e$, -4)
                        IF Error_Happened THEN GOTO errmes
                        GOTO sete
                    END IF '-4

                    IF separgs2(i) = "N-LL" THEN
                        e$ = "NULL"
                    ELSE

                        e2$ = fixoperationorder$(separgs2(i))
                        IF Error_Happened THEN GOTO errmes
                        IF convertspacing = 1 AND addlayout = 1 THEN l$ = LEFT$(l$, LEN(l$) - 1) + sp
                        IF addlayout THEN l$ = l$ + tlayout$: addedlayout = 1

                        allow_bare_member_array = 0
                        member_array_arg_source$ = ""
                        'Negative targettyp values are internal sentinel types (for example -1
                        'means "any numeric argument" for ABS). Do not interpret their set bits as
                        'real type flags such as ISARRAY.
                        IF targettyp >= 0 THEN
                            IF targettyp AND ISARRAY THEN
                                allow_bare_member_array = -1
                                member_array_arg_source$ = separgs2(i)
                            END IF
                        END IF
                        IF allow_bare_member_array THEN udt_allow_bare_array = -1
                        e$ = evaluate(e2$, sourcetyp)
                        IF allow_bare_member_array THEN udt_allow_bare_array = 0
                        IF Error_Happened THEN GOTO errmes

                        ' The source spelling memberName() is mandatory only when evaluate()
                        ' actually resolved the dotted operand to a final UDT member whose metadata
                        ' says that the final member itself is an array.  Parent UDT arrays and
                        ' scalar members such as block.SIZE must not trigger this rule.
                        IF member_array_arg_source$ <> "" THEN
                            IF INSTR(member_array_arg_source$, ".") THEN
                                IF IsWholeMemberArrayRef%(e$, sourcetyp) THEN
                                    IF HasFinalEmptyArrayBrackets%(member_array_arg_source$) = 0 THEN a$ = "Expected: Array Name()": GOTO errmes
                                END IF
                            END IF
                        END IF

                        IF RTRIM$(id2.callname) = "sub_paint" THEN
                            IF i = 3 THEN
                                IF (sourcetyp AND ISSTRING) THEN
                                    targettyp = ISSTRING
                                END IF
                            END IF
                        END IF

                        IF LEFT$(separgs2(i), 2) = "(" + sp THEN dereference = 1 ELSE dereference = 0

                        'pass by reference
                        IF (targettyp AND ISPOINTER) THEN
                            IF dereference = 0 THEN 'check dereferencing wasn't used

                                'note: array pointer
                                IF (targettyp AND ISARRAY) THEN
                                    IF (sourcetyp AND ISREFERENCE) = 0 THEN a$ = "Expected arrayname()": GOTO errmes
                                    IF (sourcetyp AND ISARRAY) = 0 THEN a$ = "Expected arrayname()": GOTO errmes
                                    IF Debug THEN PRINT #9, "sub:array reference:[" + e$ + "]"

                                    'check arrays are of same type
                                    targettyp2 = targettyp: sourcetyp2 = sourcetyp
                                    targettyp2 = targettyp2 AND (UDTMASK + ISOFFSETINBITS + ISUDT + ISSTRING + ISFIXEDLENGTH + ISFLOAT)
                                    sourcetyp2 = sourcetyp2 AND (UDTMASK + ISOFFSETINBITS + ISUDT + ISSTRING + ISFIXEDLENGTH + ISFLOAT)
                                    IF sourcetyp2 <> targettyp2 THEN a$ = "Incorrect array type passed to sub": GOTO errmes


                                    member_element_id = 0

                                    'check arrayname was followed by '()'
                                    IF RIGHT$(e$, 2) = sp3 + "0" THEN
                                        ' classic whole-array reference: array()
                                    ELSE
                                        s1 = INSTR(e$, sp3)
                                        IF s1 THEN
                                            s2 = INSTR(s1 + LEN(sp3), e$, sp3)
                                        ELSE
                                            s2 = 0
                                        END IF

                                        IF s2 THEN
                                            s3 = INSTR(s2 + LEN(sp3), e$, sp3)
                                        ELSE
                                            s3 = 0
                                        END IF

                                        IF s3 = 0 THEN a$ = "Expected arrayname()": GOTO errmes

                                        member_element_id = VAL(MID$(e$, s2 + LEN(sp3), s3 - s2 - LEN(sp3)))
                                        o$ = MID$(e$, s3 + LEN(sp3))

                                        IF member_element_id > 0 THEN
                                            IF udtearrayelements(member_element_id) = 0 THEN a$ = "Expected arrayname()": GOTO errmes
                                            ' whole TYPE member-array reference; storage mode is resolved from member metadata
                                        ELSEIF LEFT$(o$, 4) = "(0)*" OR LEFT$(o$, 5) = "((0)*" THEN
                                            ' classic whole UDT array reference
                                        ELSE
                                            a$ = "Expected arrayname()": GOTO errmes
                                        END IF
                                    END IF

                                    idnum = VAL(LEFT$(e$, INSTR(e$, sp3) - 1))
                                    getid idnum
                                    IF Error_Happened THEN GOTO errmes

                                    IF targettyp AND ISFIXEDLENGTH THEN
                                        targettypsize = CVL(MID$(id2.argsize, i * 4 - 4 + 1, 4))
                                        source_fixed_size = id.tsize
                                        IF member_element_id > 0 THEN source_fixed_size = udtetypesize(member_element_id)
                                        IF source_fixed_size <> targettypsize THEN a$ = "Incorrect array type passed to sub": GOTO errmes
                                    END IF

                                    IF MID$(sfcmemargs(targetid), i, 1) = CHR$(1) THEN 'cmem required?
                                        IF cmemlist(idnum) = 0 THEN
                                            cmemlist(idnum) = 1
                                            recompile = 1
                                        END IF
                                    END IF

                                    source_dims = 0
                                    IF member_element_id > 0 THEN
                                        source_dims = udtearraydims(member_element_id)
                                    ELSEIF id.linkid = 0 THEN
                                        'For normal arrays, dimensions are known only when this is not a
                                        'fake/unknown array descriptor. A TYPE member array always carries
                                        'its declared dimension count in udtearraydims().
                                        source_dims = id.arrayelements
                                    END IF

                                    IF source_dims > 0 THEN
                                        IF nelereq = 0 THEN
                                            nelereq = source_dims
                                            MID$(id2.nelereq, i, 1) = CHR$(nelereq)
                                            ids(targetid) = id2
                                        ELSEIF source_dims <> nelereq THEN
                                            a$ = "Passing arrays with a differing number of elements to a SUB/FUNCTION is not supported": GOTO errmes
                                        END IF
                                    END IF

                                    IF member_element_id > 0 THEN
                                        member_arg$ = "": member_prep$ = "": member_dims = 0
                                        BuildUDTMemberArg e$, member_arg$, member_prep$, member_dims
                                        IF Error_Happened THEN GOTO errmes
                                        e$ = member_arg$
                                        subargprep$ = subargprep$ + member_prep$
                                    ELSE
                                        e$ = refer(e$, sourcetyp, 1)
                                        IF Error_Happened THEN GOTO errmes
                                    END IF
                                    GOTO sete

                                END IF 'target is an array

                                'note: not an array...
                                'target is not an array

                                IF (targettyp AND ISSTRING) = 0 THEN
                                    IF (sourcetyp AND ISREFERENCE) THEN
                                        idnum = VAL(LEFT$(e$, INSTR(e$, sp3) - 1)) 'id# of sourcetyp

                                        targettyp2 = targettyp: sourcetyp2 = sourcetyp

                                        'get info about source/target
                                        arr = 0: IF (sourcetyp2 AND ISARRAY) THEN arr = 1
                                        passudtelement = 0: IF (targettyp2 AND ISUDT) = 0 AND (sourcetyp2 AND ISUDT) <> 0 THEN passudtelement = 1: sourcetyp2 = sourcetyp2 - ISUDT

                                        'remove flags irrelevant for comparison... ISPOINTER,ISREFERENCE,ISINCONVENTIONALMEMORY,ISARRAY
                                        targettyp2 = targettyp2 AND (UDTMASK + ISOFFSETINBITS + ISUDT + ISFLOAT + ISSTRING)
                                        sourcetyp2 = sourcetyp2 AND (UDTMASK + ISOFFSETINBITS + ISUDT + ISFLOAT + ISSTRING)

                                        'compare types
                                        IF sourcetyp2 = targettyp2 THEN

                                            IF sourcetyp AND ISUDT THEN
                                                'udt/udt array

                                                'get info
                                                udtrefid = VAL(e$)
                                                getid udtrefid
                                                IF Error_Happened THEN GOTO errmes
                                                udtrefi = INSTR(e$, sp3) 'end of id
                                                udtrefi2 = INSTR(udtrefi + 1, e$, sp3) 'end of u
                                                udtrefu = VAL(MID$(e$, udtrefi + 1, udtrefi2 - udtrefi - 1))
                                                udtrefi3 = INSTR(udtrefi2 + 1, e$, sp3) 'skip e
                                                udtrefe = VAL(MID$(e$, udtrefi2 + 1, udtrefi3 - udtrefi2 - 1))
                                                o$ = RIGHT$(e$, LEN(e$) - udtrefi3)
                                                'note: most of the UDT info above is not required

                                                IF arr THEN
                                                    n$ = scope$ + "ARRAY_UDT_" + RTRIM$(id.n) + "[0]"
                                                ELSE
                                                    n$ = scope$ + "UDT_" + RTRIM$(id.n)
                                                END IF

                                                e$ = "(void*)( ((char*)(" + n$ + ")) + (" + o$ + ") )"

                                                'convert void* to target type*
                                                IF passudtelement THEN e$ = "(" + typ2ctyp$(targettyp2 + (targettyp AND ISUNSIGNED), "") + "*)" + e$
                                                IF Error_Happened THEN GOTO errmes

                                            ELSE
                                                'not a udt
                                                IF arr THEN
                                                    IF (sourcetyp2 AND ISOFFSETINBITS) THEN a$ = "Cannot pass _BIT array offsets": GOTO errmes
                                                    e$ = "(&(" + refer(e$, sourcetyp, 0) + "))"
                                                    IF Error_Happened THEN GOTO errmes
                                                ELSE
                                                    e$ = refer(e$, sourcetyp, 1)
                                                    IF Error_Happened THEN GOTO errmes
                                                END IF

                                                'note: signed/unsigned mismatch requires casting
                                                IF (sourcetyp AND ISUNSIGNED) <> (targettyp AND ISUNSIGNED) THEN
                                                    e$ = "(" + typ2ctyp$(targettyp2 + (targettyp AND ISUNSIGNED), "") + "*)" + e$
                                                    IF Error_Happened THEN GOTO errmes
                                                END IF

                                            END IF 'udt?

                                            IF MID$(sfcmemargs(targetid), i, 1) = CHR$(1) THEN 'cmem required?
                                                IF cmemlist(idnum) = 0 THEN
                                                    cmemlist(idnum) = 1
                                                    recompile = 1
                                                END IF
                                            END IF

                                            GOTO sete
                                        END IF 'similar
                                    END IF 'reference
                                ELSE 'not a string
                                    'it's a string
                                    IF (sourcetyp AND ISREFERENCE) THEN
                                        idnum = VAL(LEFT$(e$, INSTR(e$, sp3) - 1)) 'id# of sourcetyp
                                        IF MID$(sfcmemargs(targetid), i, 1) = CHR$(1) THEN 'cmem required?
                                            IF cmemlist(idnum) = 0 THEN
                                                cmemlist(idnum) = 1
                                                recompile = 1
                                            END IF
                                        END IF
                                    END IF 'reference
                                END IF 'it's a string

                            END IF 'dereference check
                        END IF 'target is a pointer

                        'note: Target is not a pointer...

                        'String-numeric mismatch?
                        IF targettyp AND ISSTRING THEN
                            IF (sourcetyp AND ISSTRING) = 0 THEN
                                nth = i
                                IF ids(targetid).args = 1 THEN a$ = "String required for sub": GOTO errmes
                                a$ = str_nth$(nth) + " sub argument requires a string": GOTO errmes
                            END IF
                        END IF
                        IF (targettyp AND ISSTRING) = 0 THEN
                            IF sourcetyp AND ISSTRING THEN
                                nth = i
                                IF ids(targetid).args = 1 THEN a$ = "Number required for sub": GOTO errmes
                                a$ = str_nth$(nth) + " sub argument requires a number": GOTO errmes
                            END IF
                        END IF

                        'change to "non-pointer" value
                        IF (sourcetyp AND ISREFERENCE) THEN
                            e$ = refer(e$, sourcetyp, 0)
                            IF Error_Happened THEN GOTO errmes
                        END IF

                        IF explicitreference = 0 THEN
                            IF targettyp AND ISUDT THEN
                                nth = i
                                x$ = "'" + RTRIM$(udtxcname(targettyp AND UDTMASK)) + "'"
                                IF ids(targetid).args = 1 THEN a$ = "TYPE " + x$ + " required for sub": GOTO errmes
                                a$ = str_nth$(nth) + " sub argument requires TYPE " + x$: GOTO errmes
                            END IF
                        ELSE
                            IF sourcetyp AND ISUDT THEN a$ = "Number required for sub": GOTO errmes
                        END IF

                        'round to integer if required
                        IF (sourcetyp AND ISFLOAT) THEN
                            IF (targettyp AND ISFLOAT) = 0 THEN
                                '**32 rounding fix
                                bits = targettyp AND UDTMASK
                                IF bits <= 16 THEN e$ = "qbr_float_to_long(" + e$ + ")"
                                IF bits > 16 AND bits < 32 THEN e$ = "qbr_double_to_long(" + e$ + ")"
                                IF bits >= 32 THEN e$ = "qbr(" + e$ + ")"
                            END IF
                        END IF

                        IF (targettyp AND ISPOINTER) THEN 'pointer required
                            IF (targettyp AND ISSTRING) THEN GOTO sete 'no changes required
                            t$ = typ2ctyp$(targettyp, "")
                            IF Error_Happened THEN GOTO errmes
                            v$ = "pass" + _TOSTR$(uniquenumber)
                            'assume numeric type
                            IF MID$(sfcmemargs(targetid), i, 1) = CHR$(1) THEN 'cmem required?
                                bytesreq = ((targettyp AND UDTMASK) + 7) \ 8
                                WriteBufLine defdatahandle, t$ + " *" + v$ + "=NULL;"
                                WriteBufLine DataTxtBuf, "if(" + v$ + "==NULL){"
                                WriteBufLine DataTxtBuf, "cmem_sp-=" + _TOSTR$(bytesreq) + ";"
                                WriteBufLine DataTxtBuf, v$ + "=(" + t$ + "*)(dblock+cmem_sp);"
                                WriteBufLine DataTxtBuf, "if (cmem_sp<qbs_cmem_sp) error(257);"
                                WriteBufLine DataTxtBuf, "}"
                                e$ = "&(*" + v$ + "=" + e$ + ")"
                            ELSE
                                WriteBufLine DataTxtBuf, t$ + " " + v$ + ";"
                                e$ = "&(" + v$ + "=" + e$ + ")"
                            END IF
                            GOTO sete
                        END IF

                    END IF 'not "NULL"

                    sete:

                    IF RTRIM$(id2.callname) = "sub_paint" THEN
                        IF i = 3 THEN
                            IF (sourcetyp AND ISSTRING) THEN
                                e$ = "(qbs*)" + e$
                            ELSE
                                e$ = "(uint32)" + e$
                            END IF
                        END IF
                    END IF

                    IF id2.ccall THEN

                        'if a forced cast from a returned ccall function is in e$, remove it
                        IF LEFT$(e$, 3) = "(  " THEN
                            e$ = removecast$(e$)
                        END IF

                        IF targettyp AND ISSTRING THEN
                            e$ = "(char*)(" + e$ + ")->chr"
                        END IF

                        IF LTRIM$(RTRIM$(e$)) = "0" THEN e$ = "NULL"

                    END IF

                    IF i <> 1 THEN subcall$ = subcall$ + ","
                    subcall$ = subcall$ + e$
                NEXT

                'note: i=id.args+1
                x$ = separgslayout2$(i)
                DO WHILE LEN(x$)
                    x = ASC(x$)
                    IF x THEN
                        x2$ = MID$(x$, 2, x)
                        x$ = RIGHT$(x$, LEN(x$) - x - 1)

                        s = 0
                        an = 0
                        x3$ = RIGHT$(l$, 1)
                        IF x3$ = sp THEN s = 1
                        IF x3$ = sp2 THEN
                            s = 2
                            IF alphanumeric(ASC(RIGHT$(l$, 2))) THEN an = 1
                            'if asc(right$(l$,2))=34 then an=1
                        ELSE
                            IF alphanumeric(ASC(x3$)) THEN an = 1
                            'if asc(x3$)=34 then an=1
                        END IF
                        s1 = s

                        IF (an = 1 OR addedlayout = 1) AND alphanumeric(ASC(x2$)) <> 0 THEN
                            s = 1 'force space
                            x2$ = x2$ + sp2
                            GOTO customlaychar2
                        END IF

                        IF x2$ = "=" THEN
                            s = 1
                            x2$ = x2$ + sp
                            GOTO customlaychar2
                        END IF

                        IF x2$ = "#" THEN
                            s = 1
                            x2$ = x2$ + sp2
                            GOTO customlaychar2
                        END IF

                        IF x2$ = "," THEN x2$ = x2$ + sp: GOTO customlaychar2

                        IF x$ = CHR$(0) THEN 'substitution
                            IF x2$ = "STEP" THEN x2$ = SCase$("Step") + sp2: GOTO customlaychar2
                            x2$ = x2$ + sp: GOTO customlaychar2
                        END IF

                        'default solution sp2+?+sp2
                        x2$ = x2$ + sp2
                        customlaychar2:
                        IF s = 0 THEN s = 2
                        IF s <> s1 THEN
                            IF s1 THEN l$ = LEFT$(l$, LEN(l$) - 1)
                            IF s = 1 THEN l$ = l$ + sp
                            IF s = 2 THEN l$ = l$ + sp2
                        END IF
                        l$ = l$ + x2$

                    ELSE
                        addlayout = 0
                        x$ = RIGHT$(x$, LEN(x$) - 1)
                    END IF
                    addedlayout = 0
                LOOP






                IF passedneeded THEN
                    subcall$ = subcall$ + "," + _TOSTR$(passed&)
                END IF
                subcall$ = subcall$ + ");"
                IF subargprep$ <> "" THEN subcall$ = "[&](){" + subargprep$ + subcall$ + "}();"

                IF firstelement$ = "SLEEP" THEN
                    IF GetRCStateVar(vWatchOn) THEN
                        WriteBufLine MainTxtBuf, "*__LONG_VWATCH_LINENUMBER= -4; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars);"
                    END IF
                END IF

                WriteBufLine MainTxtBuf, subcall$
                IF dynfilepost$ <> "" THEN WriteBufLine MainTxtBuf, dynfilepost$

                IF firstelement$ = "SLEEP" THEN
                    IF GetRCStateVar(vWatchOn) THEN
                        WriteBufLine MainTxtBuf, "*__LONG_VWATCH_LINENUMBER= -5; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars);"
                    END IF
                END IF

                subcall$ = ""
                IF stringprocessinghappened THEN WriteBufLine MainTxtBuf, cleanupstringprocessingcall$ + "0);"

                layoutdone = 1
                x$ = RIGHT$(l$, 1): IF x$ = sp OR x$ = sp2 THEN l$ = LEFT$(l$, LEN(l$) - 1)
                IF usecall = 1 THEN l$ = l$ + sp2 + ")"
                IF Debug THEN PRINT #9, "SUB layout:[" + l$ + "]"
                IF LEN(layout$) = 0 THEN layout$ = l$ ELSE layout$ = layout$ + sp + l$
                GOTO finishedline


            END IF

            IF try = 2 THEN
                findidsecondarg = "": IF n >= 2 THEN findidsecondarg = getelement$(a$, 2)
                findanotherid = 1
                try = findid(firstelement$)
                IF Error_Happened THEN GOTO errmes
            ELSE
                try = 0
            END IF
        LOOP

    END IF

    notsubcall:

    IF n >= 1 THEN
        IF firstelement$ = "LET" THEN
            IF n = 1 THEN a$ = "Syntax error - Reference: LET variable = expression (tip: LET is entirely optional)": GOTO errmes
            ca$ = RIGHT$(ca$, LEN(ca$) - 4)
            n = n - 1
            l$ = SCase$("Let")
            IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
            'note: layoutdone=1 will be set later
            GOTO letused
        END IF
    END IF

    'LET ???=???
    IF n >= 3 THEN
        IF INSTR(a$, sp + "=" + sp) THEN
            letused:
            assign ca$, n
            IF Error_Happened THEN GOTO errmes
            layoutdone = 1
            IF LEN(layout$) = 0 THEN layout$ = tlayout$ ELSE layout$ = layout$ + sp + tlayout$
            GOTO finishedline
        END IF
    END IF '>=3
    IF RIGHT$(a$, 2) = sp + "=" THEN a$ = "Expected ... = expression": GOTO errmes

    'Syntax error
    a$ = "Syntax error": GOTO errmes

    finishedline:
    THENGOTO = 0
    finishedline2:

    IF inputfunctioncalled THEN
        inputfunctioncalled = 0
        IF GetRCStateVar(vWatchOn) THEN
            WriteBufLine MainTxtBuf, "*__LONG_VWATCH_LINENUMBER= -5; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars);"
        END IF
    END IF

    IF arrayprocessinghappened = 1 THEN arrayprocessinghappened = 0

    inclinenump$ = ""
    IF inclinenumber(inclevel) THEN
        inclinenump$ = "," + _TOSTR$(inclinenumber(inclevel))
        thisincname$ = getfilepath$(incname$(inclevel))
        thisincname$ = MID$(incname$(inclevel), LEN(thisincname$) + 1)
        inclinenump$ = inclinenump$ + "," + CHR$(34) + thisincname$ + CHR$(34)
    END IF
    IF CheckingOn THEN
        IF GetRCStateVar(vWatchOn) = 1 AND inclinenumber(inclevel) = 0 THEN temp$ = vWatchErrorCall$ ELSE temp$ = ""
        IF dynscope THEN
            dynscope = 0
            WriteBufLine MainTxtBuf, "if(qbevent){" + temp$ + "evnt(" + _TOSTR$(linenumber) + inclinenump$ + ");if(r)goto S_" + _TOSTR$(statementn) + ";}"
        ELSE
            WriteBufLine MainTxtBuf, "if(!qbevent)break;" + temp$ + "evnt(" + _TOSTR$(linenumber) + inclinenump$ + ");}while(r);"
        END IF
    END IF

    finishednonexec:

    IF layoutdone = 0 THEN layoutok = 0 'invalidate layout if not handled

    IF continuelinefrom = 0 THEN 'note: manager #2 requires this condition

        'Include Manager #2 '***
        IF LEN(addmetainclude$) THEN

            IF inclevel = 0 THEN
                'backup line formatting
                layoutcomment_backup$ = layoutcomment$
                layoutok_backup = layoutok
                layout_backup$ = layout$
                layoutoriginal_backup$ = layoutoriginal$
                idecompiledline_backup$ = idecompiledline$
                IDEAutoIndent_backup = IDEAutoIndent
                IDEAutoLayout_backup = IDEAutoLayout
            END IF

            a$ = addmetainclude$: addmetainclude$ = "" 'read/clear message

            IF inclevel = 0 THEN
                includingFromRoot = 0
                autoIncludingFile = 0
                autoInclude:
                IF autoIncludeBuffer <> -1 THEN
                    a$ = ReadBufLine$(autoIncludeBuffer)
                    IF a$ = "-----" THEN mainEndLine = 3: GOTO autoInclude '"AfterMain" is done
                    autoIncludingFile = 1
                    IF RIGHT$(a$, 18) = "beforefirstline.bi" OR RIGHT$(a$, 16) = "afterlastline.bm" THEN
                        autoIncludingFile = -1
                    END IF
                    includingFromRoot = 1
                END IF
            END IF

            IF inclevel = 100 THEN
                FOR fh = 200 TO 299: CLOSE #fh: NEXT fh 'close all includes
                a$ = "Too many indwelling INCLUDE files": GOTO errmes
            END IF
            '1. Verify file exists (location is either (a)relative to source file or (b)absolute)
            IF LEFT$(a$, 2) = ".\" OR LEFT$(a$, 2) = "./" THEN a$ = MID$(a$, 3)
            fh = 199 + inclevel + 1

            firstTryMethod = 1
            IF includingFromRoot <> 0 AND inclevel = 0 THEN firstTryMethod = 2
            FOR try = firstTryMethod TO 2 'if including file from root, do not attempt including from relative location
                IF try = 1 THEN
                    IF inclevel = 0 THEN
                        IF idemode THEN p$ = idepath$ + pathsep$ ELSE p$ = getfilepath$(sourcefile$)
                    ELSE
                        p$ = getfilepath$(incname$(inclevel))
                    END IF
                    f$ = p$ + a$
                END IF
                IF try = 2 THEN f$ = a$
                IF _FILEEXISTS(f$) THEN
                    qberrorhappened = -2 '***
                    OPEN f$ FOR BINARY AS #fh
                    qberrorhappened2: '***
                    IF qberrorhappened = -2 THEN
                        '=== BEGIN: handling $INCLUDEONCE ===
                        incDAT$ = SPACE$(LOF(fh))
                        GET #fh, , incDAT$
                        CLOSE #fh 'as we skip the regular CLOSE when $INCLUDEONCE
                        incDAT$ = UCASE$(incDAT$)
                        incPOS& = INSTR(incDAT$, "$INCLUDEONCE" + MKI$(&H0A0D))
                        IF incPOS& = 0 OR incPOS& > 1 THEN
                            IF incPOS& = 0 THEN incPOS& = INSTR(incDAT$, "$INCLUDEONCE" + CHR$(10))
                            IF incPOS& = 0 OR incPOS& > 1 THEN
                                incPOS& = INSTR(incDAT$, CHR$(10) + "$INCLUDEONCE" + MKI$(&H0A0D))
                                IF incPOS& = 0 THEN incPOS& = INSTR(incDAT$, CHR$(10) + "$INCLUDEONCE" + CHR$(10))
                            END IF
                        END IF
                        IF incPOS& > 0 THEN
                            nul& = SeekBuf&(IncOneBuf, 0, SBM_BufStart)
                            WHILE NOT EndOfBuf%(IncOneBuf)
                                IF _FULLPATH$(f$) = ReadBufLine$(IncOneBuf) THEN
                                    qberrorhappened = 0
                                    GOTO skipInc2
                                END IF
                            WEND
                        END IF
                        WriteBufLine IncOneBuf, _FULLPATH$(f$)
                        WriteBufLine ExtDepBuf, "INCL: " + _FULLPATH$(f$)
                        OPEN f$ FOR BINARY AS #fh 'reopen and continue
                        '=== END: handling $INCLUDEONCE ===
                        EXIT FOR '***
                    END IF
                END IF
                qberrorhappened = 0
            NEXT
            IF qberrorhappened <> -2 THEN qberrorhappened = 0: a$ = "File " + a$ + " not found": GOTO errmes
            qberrorhappened = 0
            inclevel = inclevel + 1: incname$(inclevel) = f$: inclinenumber(inclevel) = 0
        END IF 'fall through to next section...
        '--------------------
        DO WHILE inclevel
            fh = 199 + inclevel
            '2. Feed next line
            IF EOF(fh) = 0 THEN
                LINE INPUT #fh, x$
                a3$ = x$
                continuelinefrom = 0
                inclinenumber(inclevel) = inclinenumber(inclevel) + 1
                'create extended error string 'incerror$'
                errorLineInInclude = inclinenumber(inclevel)
                e$ = " in line " + _TOSTR$(inclinenumber(inclevel)) + " of " + incname$(inclevel)
                IF autoIncludingFile <> 0 THEN e$ = e$ + " auto-included" ELSE e$ = e$ + " included"
                IF inclevel > 1 THEN
                    e$ = e$ + " (through "
                    FOR x = 1 TO inclevel - 1 STEP 1
                        e$ = e$ + incname$(x)
                        IF x < inclevel - 1 THEN 'a sep is req
                            IF x = inclevel - 2 THEN
                                e$ = e$ + " then "
                            ELSE
                                e$ = e$ + ", "
                            END IF
                        END IF
                    NEXT
                    e$ = e$ + ")"
                END IF
                incerror$ = e$
                linenumber = linenumber - 1 'lower official linenumber to counter later increment
                IF idemode THEN sendc$ = CHR$(10) + a3$: GOTO sendcommand 'passback
                GOTO compileline
            END IF
            '3. Close & return control
            CLOSE #fh
            inclevel = inclevel - 1
            skipInc2:
            IF (inclevel = 0 OR mainEndLine = 2) THEN
                IF autoIncludingFile <> 0 THEN
                    IF NOT EndOfBuf%(autoIncludeBuffer) GOTO autoInclude
                END IF
                IF inclevel = 0 THEN
                    'restore line formatting
                    layoutok = layoutok_backup
                    layout$ = layout_backup$
                    layoutcomment$ = layoutcomment_backup$
                    layoutoriginal$ = layoutoriginal_backup$
                    idecompiledline$ = idecompiledline_backup$
                    IDEAutoIndent = IDEAutoIndent_backup
                    IDEAutoLayout = IDEAutoLayout_backup
                END IF
                IF autoIncludingFile <> 0 THEN
                    autoIncludingFile = 0
                    RETURN 'to auto-include manager
                END IF
            END IF
        LOOP 'fall through to next section...
        '(end manager)

    END IF 'continuelinefrom=0


    IF Debug THEN
        PRINT #9, "[layout check]"
        PRINT #9, "[" + layoutoriginal$ + "]"
        PRINT #9, "[" + layout$ + "]"
        PRINT #9, layoutok
        PRINT #9, "[end layout check]"
    END IF

    IF continuelinefrom THEN GOTO compileline 'continue processing other commands on line

    IF LEN(layoutcomment$) THEN
        IF LEN(layout$) THEN layout$ = layout$ + sp + layoutcomment$ ELSE layout$ = layoutcomment$
    END IF

    IF layoutok = 0 THEN
        layout$ = _TRIM$(layoutoriginal$)
    ELSE
        'reverse '046' changes present in autolayout
        layout$ = StrReplace$(layout$, fix046$, ".")
    END IF
    x = lhscontrollevel: IF controllevel < lhscontrollevel THEN x = controllevel
    IF definingtype = 2 THEN x = x + 1
    IF definingtype > 0 THEN definingtype = 2
    IF declaringlibrary = 2 THEN x = x + 1
    IF declaringlibrary > 0 THEN declaringlibrary = 2
    layout$ = SPACE$(x) + layout$
    IF linecontinuation THEN layout$ = ""

    IF idemode THEN GOTO ideret4 'return control to IDE
    IF lastLineReturn = 1 THEN EXIT DO

    skip_invalidated_line:
    IF FormatMode THEN
        IF linecontinuation THEN
            'This line has a _ for continuation so will not be formatted. Use the original line as read plus
            'any continued physical lines
            WriteBufLine FormatBuf, layoutoriginal$ + layoutcontinuations
        ELSE
            indented$ = apply_layout_indent$(layoutoriginal$)
            IF LEN(indented$) THEN WriteBufLine FormatBuf, indented$ ELSE WriteBufLine FormatBuf, layoutoriginal$
        END IF
    END IF
LOOP

'add final line
IF lastLineReturn = 0 THEN
    lastLineReturn = 1
    lastLine = 1
    a3$ = ""
    GOTO compileline
END IF

ide5:
linenumber = 0
closemain

IF definingtype THEN linenumber = definingtypeerror: a$ = "TYPE without END TYPE": GOTO errmes

'check for open controls (copy #1)
IF controllevel THEN
    a$ = "Unidentified open control block"
    SELECT CASE controltype(controllevel)
        CASE 1: a$ = "IF without END IF"
        CASE 2: a$ = "FOR without NEXT"
        CASE 3, 4: a$ = "DO without LOOP"
        CASE 5: a$ = "WHILE without WEND"
        CASE 6: a$ = "$IF without $END IF"
        CASE 10 TO 19: a$ = "SELECT CASE without END SELECT"
        CASE 32: a$ = "SUB/FUNCTION without END SUB/FUNCTION"
    END SELECT
    linenumber = controlref(controllevel)
    GOTO errmes
END IF

IF IDEIndentSubs = 0 THEN
    IF LEN(subfunc) THEN a$ = "SUB/FUNCTION without END SUB/FUNCTION": GOTO errmes
END IF

'close the error handler (cannot be put in 'closemain' because subs/functions can also add error jumps to this file)
WriteBufLine ErrTxtBuf, "exit(99);" 'in theory this line should never be run!
WriteBufLine ErrTxtBuf, "}" 'close error jump handler

'create CLEAR method "CLEAR"
MainTxtBuf = OpenBuffer%("O", tmpdir$ + "clear.txt")

FOR i = 1 TO idn

    IF ids(i).staticscope THEN 'static scope?
        subfunc = RTRIM$(ids(i).insubfunc) 'set static scope
        GOTO clearstaticscope
    END IF

    a = ASC(ids(i).insubfunc)
    IF a = 0 OR a = 32 THEN 'global scope?
        subfunc = "" 'set global scope
        clearstaticscope:

        IF ids(i).arraytype THEN 'an array
            getid i
            IF Error_Happened THEN GOTO errmes
            IF id.arrayelements = -1 THEN GOTO clearerasereturned 'cannot erase non-existent array
            IF INSTR(vWatchVariableExclusions$, "@" + RTRIM$(id.callname) + "@") > 0 THEN
                GOTO clearerasereturned
            END IF
            clearerasereturn = 1: GOTO clearerase
        END IF 'array

        IF ids(i).t THEN 'non-array variable
            getid i
            IF Error_Happened THEN GOTO errmes
            bytes$ = variablesize$(-1)
            IF Error_Happened THEN GOTO errmes
            'create a reference
            typ = id.t + ISREFERENCE
            IF typ AND ISUDT THEN
                e$ = _TOSTR$(i) + sp3 + _TOSTR$(typ AND UDTMASK) + sp3 + "0" + sp3 + "0"
            ELSE
                e$ = _TOSTR$(i)
            END IF
            e$ = refer$(e$, typ, 1)
            IF Error_Happened THEN GOTO errmes
            IF typ AND ISSTRING THEN
                IF typ AND ISFIXEDLENGTH THEN
                    WriteBufLine MainTxtBuf, "memset((void*)(" + e$ + "->chr),0," + bytes$ + ");"
                    GOTO cleared
                ELSE
                    IF INSTR(vWatchVariableExclusions$, "@" + e$ + "@") = 0 AND LEFT$(e$, 12) <> "_SUB_VWATCH_" THEN
                        WriteBufLine MainTxtBuf, e$ + "->len=0;"
                    END IF
                    GOTO cleared
                END IF
            END IF
            IF typ AND ISUDT THEN
                IF udtxvariable(typ AND UDTMASK) THEN
                    'this next procedure resets values of UDT variables with variable-length strings
                    clear_udt_with_varstrings e$, typ AND UDTMASK, MainTxtBuf, 0
                ELSE
                    WriteBufLine MainTxtBuf, "memset((void*)" + e$ + ",0," + bytes$ + ");"
                END IF
            ELSE
                IF INSTR(vWatchVariableExclusions$, "@" + e$ + "@") = 0 AND LEFT$(e$, 12) <> "_SUB_VWATCH_" THEN
                    WriteBufLine MainTxtBuf, "*" + e$ + "=0;"
                END IF
            END IF
            GOTO cleared
        END IF 'non-array variable

    END IF 'scope

    cleared:
    clearerasereturned:
NEXT

IF Debug THEN
    PRINT #9, "finished making program!"
    PRINT #9, "recompile="; recompile
END IF

'Set cmem flags for subs/functions requiring data passed in cmem
FOR i = 1 TO idn
    IF cmemlist(i) THEN 'must be in cmem

        getid i
        IF Error_Happened THEN GOTO errmes

        IF Debug THEN PRINT #9, "recompiling cmem sf! checking:"; RTRIM$(id.n)

        IF id.sfid THEN 'it is an argument of a sub/function

            IF Debug THEN PRINT #9, "recompiling cmem sf! It's a sub/func arg!"

            i2 = id.sfid
            x = id.sfarg

            IF Debug THEN PRINT #9, "recompiling cmem sf! values:"; i2; x

            'check if cmem flag is set, if not then set it & force recompile
            IF MID$(sfcmemargs(i2), x, 1) <> CHR$(1) THEN
                MID$(sfcmemargs(i2), x, 1) = CHR$(1)


                IF Debug THEN PRINT #9, "recompiling cmem sf! setting:"; i2; x


                recompile = 1
            END IF
        END IF
    END IF
NEXT i

unresolved = 0
FOR i = 1 TO idn
    getid i
    IF Error_Happened THEN GOTO errmes

    IF Debug THEN PRINT #9, "checking id named:"; id.n

    IF id.subfunc THEN
        FOR i2 = 1 TO id.args
            t = CVL(MID$(id.arg, i2 * 4 - 3, 4))
            IF t > 0 THEN
                IF (t AND ISPOINTER) THEN
                    IF (t AND ISARRAY) THEN

                        IF Debug THEN PRINT #9, "checking argument "; i2; " of "; id.args

                        nele = ASC(MID$(id.nele, i2, 1))
                        nelereq = ASC(MID$(id.nelereq, i2, 1))

                        IF Debug THEN PRINT #9, "nele="; nele
                        IF Debug THEN PRINT #9, "nelereq="; nelereq

                        IF nele <> nelereq THEN

                            IF Debug THEN PRINT #9, "mismatch detected!"

                            unresolved = unresolved + 1
                            sflistn = sflistn + 1
                            IF sflistn > 25000 THEN 'manually set a descriptive error message for the user so they know what's happening.
                                Error_Message = "ERROR: QB64PE currently limits a program to have a maximum of 25,000 subs and functions, and this limit has been exceeded.  Please reduce Sub/Function count, or else report this issue with sample code that produced it over at the QB64PE forums, so we can look further into this issue."
                                GOTO errmes
                            END IF
                            ubound_sf = UBOUND(sfidlist) 'all 3 should have the same limit
                            IF sflistn > ubound_sf THEN
                                REDIM _PRESERVE sfidlist(ubound_sf + 1000) AS LONG
                                REDIM _PRESERVE sfarglist(ubound_sf + 1000) AS INTEGER
                                REDIM _PRESERVE sfelelist(ubound_sf + 1000) AS INTEGER
                            END IF
                            sfidlist(sflistn) = i
                            sfarglist(sflistn) = i2
                            sfelelist(sflistn) = nelereq '0 means still unknown
                        END IF
                    END IF
                END IF
            END IF
        NEXT
    END IF
NEXT

'is recompilation required to resolve this?
IF unresolved > 0 THEN
    IF lastunresolved = -1 THEN
        'first pass
        recompile = 1
        IF Debug THEN
            PRINT #9, "recompiling to resolve array elements (first time)"
            PRINT #9, "sflistn="; sflistn
            PRINT #9, "oldsflistn="; oldsflistn
        END IF
    ELSE
        'not first pass
        IF unresolved < lastunresolved THEN
            recompile = 1
            IF Debug THEN
                PRINT #9, "recompiling to resolve array elements (not first time)"
                PRINT #9, "sflistn="; sflistn
                PRINT #9, "oldsflistn="; oldsflistn
            END IF
        END IF
    END IF
END IF 'unresolved
lastunresolved = unresolved

'IDEA!
'have a flag to record if anything gets resolved in a pass
'if not then it's time to stop
'the problem is the same amount of new problems may be created by a
'resolve as those that get fixed
'also/or.. could it be that previous fixes are overridden in a recompile
'          by a new fix? if so, it would give these effects



'could recompilation resolve this?
'IF sflistn <> -1 THEN
'IF sflistn <> oldsflistn THEN
'recompile = 1
'
'if debug then
'print #9,"recompile set to 1 to resolve array elements"
'print #9,"sflistn=";sflistn
'print #9,"oldsflistn=";oldsflistn
'end if
'
'END IF
'END IF

IF Debug THEN PRINT #9, "Beginning COMMON array list check..."
xi = 1
FOR x = 1 TO commonarraylistn
    varname$ = getelement$(commonarraylist, xi): xi = xi + 1
    typ$ = getelement$(commonarraylist, xi): xi = xi + 1
    dimmethod2 = VAL(getelement$(commonarraylist, xi)): xi = xi + 1
    dimshared2 = VAL(getelement$(commonarraylist, xi)): xi = xi + 1
    'find the array ID (try method)
    t = typname2typ(typ$)
    IF Error_Happened THEN GOTO errmes
    IF (t AND ISUDT) = 0 THEN varname$ = varname$ + type2symbol$(typ$)
    IF Error_Happened THEN GOTO errmes

    IF Debug THEN PRINT #9, "Checking for array '" + varname$ + "'..."

    try = findid(varname$)
    IF Error_Happened THEN GOTO errmes
    DO WHILE try
        IF id.arraytype THEN GOTO foundcommonarray2
        IF try = 2 THEN findanotherid = 1: try = findid(varname$) ELSE try = 0
        IF Error_Happened THEN GOTO errmes
    LOOP
    foundcommonarray2:

    IF Debug THEN PRINT #9, "Found array '" + varname$ + "!"

    IF id.arrayelements = -1 THEN
        IF arrayelementslist(currentid) <> 0 THEN recompile = 1
        IF Debug THEN PRINT #9, "Recompiling to resolve elements of:" + varname$
    END IF
NEXT
IF Debug THEN PRINT #9, "Finished COMMON array list check!"

IF recompile THEN
    do_recompile:
    IF Debug THEN PRINT #9, "Recompile required!"
    recompile = 0
    IF idemode THEN iderecompile = 1
    FOR closeall = 1 TO 300: CLOSE closeall: NEXT
    OPEN tmpdir$ + "temp.bin" FOR OUTPUT LOCK WRITE AS #26 'relock
    GOTO recompile
END IF

IF Debug THEN PRINT #9, "Beginning label check..."
FOR r = 1 TO nLabels

    IF Labels(r).Scope_Restriction THEN
        a$ = RTRIM$(Labels(r).cn)
        ignore = validlabel(a$)
        v = HashFind(a$, HASHFLAG_LABEL, ignore, r2)
        addlabchk7:
        IF v THEN
            IF Labels(r2).Scope = Labels(r).Scope_Restriction THEN
                linenumber = Labels(r).Error_Line: a$ = "Common label within a SUB/FUNCTION": GOTO errmes
            END IF
            IF v = 2 THEN v = HashFindCont(ignore, r2): GOTO addlabchk7
        END IF 'v
    END IF 'restriction

    'check for undefined labels
    IF Labels(r).State = 0 THEN

        IF INSTR(PossibleSubNameLabels$, sp + UCASE$(RTRIM$(Labels(r).cn)) + sp) THEN
            IF INSTR(SubNameLabels$, sp + UCASE$(RTRIM$(Labels(r).cn)) + sp) = 0 THEN 'not already added
                SubNameLabels$ = SubNameLabels$ + UCASE$(RTRIM$(Labels(r).cn)) + sp
                IF Debug THEN PRINT #9, "Recompiling to resolve label:"; RTRIM$(Labels(r).cn)
                GOTO do_recompile
            END IF
        END IF

        linenumber = Labels(r).Error_Line: a$ = "Label '" + RTRIM$(Labels(r).cn) + "' not defined": GOTO errmes
    END IF


    IF Labels(r).Data_Referenced THEN

        'check for ambiguous RESTORE reference
        x = 0
        a$ = RTRIM$(Labels(r).cn)
        ignore = validlabel(a$)
        v = HashFind(a$, HASHFLAG_LABEL, ignore, r2)
        addlabchk4:
        IF v THEN
            x = x + 1
            IF v = 2 THEN v = HashFindCont(ignore, r2): GOTO addlabchk4
        END IF 'v
        IF x <> 1 THEN linenumber = Labels(r).Error_Line: a$ = "Ambiguous DATA label": GOTO errmes

        'add global data offset variable
        WriteBufLine GlobTxtBuf, "ptrszint data_at_LABEL_" + a$ + "=" + _TOSTR$(Labels(r).Data_Offset) + ";"

    END IF 'data referenced

NEXT
IF Debug THEN PRINT #9, "Finished check!"


'if targettyp=-4 or targettyp=-5 then '? -> byte_element(offset,element size in bytes)
' IF (sourcetyp AND ISREFERENCE) = 0 THEN a$ = "Expected variable name/array element": GOTO errmes


'create include files for COMMON arrays

'return to 'main'
subfunc$ = ""
defdatahandle = GlobTxtBuf
DataTxtBuf = OpenBuffer%("A", tmpdir$ + "maindata.txt")
FreeTxtBuf = OpenBuffer%("A", tmpdir$ + "mainfree.txt")

IF GetRCStateVar(ConsoleOn) THEN
    WriteBufLine GlobTxtBuf, "int32 console=1;"
ELSE
    WriteBufLine GlobTxtBuf, "int32 console=0;"
END IF

IF ScreenHideOn THEN
    WriteBufLine GlobTxtBuf, "int32 screen_hide_startup=1;"
ELSE
    WriteBufLine GlobTxtBuf, "int32 screen_hide_startup=0;"
END IF

IF GetRCStateVar(AssertsOn) THEN
    WriteBufLine GlobTxtBuf, "int32 asserts=1;"
ELSE
    WriteBufLine GlobTxtBuf, "int32 asserts=0;"
END IF

IF GetRCStateVar(vWatchOn) THEN
    WriteBufLine GlobTxtBuf, "int32 vwatch=-1;"
ELSE
    WriteBufLine GlobTxtBuf, "int32 vwatch=0;"
END IF

bh = OpenBuffer%("A", tmpdir$ + "dyninfo.txt")
IF ResizeOn THEN
    WriteBufLine bh, "ScreenResize=1;"
END IF
IF ResizeScale THEN
    WriteBufLine bh, "ScreenResizeScale=" + _TOSTR$(ResizeScale) + ";"
END IF

IF GetRCStateVar(vWatchOn) THEN
    vWatchVariable "", 1
END IF


'DATA_finalize
WriteBufLine GlobTxtBuf, "ptrszint data_size=" + _TOSTR$(DataOffset) + ";"
IF DataOffset = 0 THEN

    WriteBufLine GlobTxtBuf, "uint8 *data=(uint8*)calloc(1,1);"

ELSE

    'inline data
    ff = OpenBuffer%("B", tmpdir$ + "data.bin")
    x$ = ReadBufRawData$(ff, GetBufLen&(ff))

    idsL = LEN(inlinedatastr(255))
    xL = LEN(x$)

    x2$ = SPACE$(xL * idsL) ' pre-allocate buffer

    x2Ofs = 1
    FOR i = 1 TO xL
        MID$(x2$, x2Ofs, idsL) = inlinedatastr(ASC(x$, i))
        x2Ofs = x2Ofs + idsL
    NEXT

    WriteBufLine GlobTxtBuf, "uint8 inline_data[]={"
    WriteBufLine GlobTxtBuf, x2$
    WriteBufLine GlobTxtBuf, "0};"
    WriteBufLine GlobTxtBuf, "uint8 *data=&inline_data[0];"

    x$ = "": x2$ = ""

END IF

IF Debug THEN PRINT #9, "Beginning generation of code for saving/sharing common array data..."
use_global_byte_elements = 1
ncommontmp = 0
xi = 1
FOR x = 1 TO commonarraylistn
    varname$ = getelement$(commonarraylist, xi): xi = xi + 1
    typ$ = getelement$(commonarraylist, xi): xi = xi + 1
    dimmethod2 = VAL(getelement$(commonarraylist, xi)): xi = xi + 1
    dimshared2 = VAL(getelement$(commonarraylist, xi)): xi = xi + 1

    'find the array ID (try method)
    purevarname$ = varname$
    t = typname2typ(typ$)
    IF Error_Happened THEN GOTO errmes
    IF (t AND ISUDT) = 0 THEN varname$ = varname$ + type2symbol$(typ$)
    IF Error_Happened THEN GOTO errmes
    try = findid(varname$)
    IF Error_Happened THEN GOTO errmes
    DO WHILE try
        IF id.arraytype THEN GOTO foundcommonarray
        IF try = 2 THEN findanotherid = 1: try = findid(varname$) ELSE try = 0
        IF Error_Happened THEN GOTO errmes
    LOOP
    a$ = "COMMON array unlocatable": GOTO errmes 'should never happen
    foundcommonarray:
    IF Debug THEN PRINT #9, "Found common array '" + varname$ + "'!"

    i = currentid
    arraytype = id.arraytype
    arrayelements = id.arrayelements
    e$ = RTRIM$(id.n)
    IF (t AND ISUDT) = 0 THEN e$ = e$ + typevalue2symbol$(t)
    IF Error_Happened THEN GOTO errmes
    n$ = e$
    n2$ = RTRIM$(id.callname)
    tsize = id.tsize

    'select command
    command = 3 'fixed length elements
    IF t AND ISSTRING THEN
        IF (t AND ISFIXEDLENGTH) = 0 THEN
            command = 4 'var-len elements
        END IF
    END IF


    'if...
    'i) array elements are still undefined (ie. arrayelements=-1) pass the input content along
    '   if any existed or an array-placeholder
    'ii) if the array's elements were defined, any input content would have been loaded so the
    '    array (in whatever state it currently is) should be passed. If it is currently erased
    '    then it should be passed as a placeholder

    IF arrayelements = -1 THEN

        'load array (copies the array, if any, into a buffer for later)



        MainTxtBuf = OpenBuffer%("O", tmpdir$ + "inpchain" + _TOSTR$(i) + ".txt")
        WriteBufLine MainTxtBuf, "if (int32val==2){" 'array place-holder
        'create buffer to store array as-is in global.txt
        x$ = _TOSTR$(uniquenumber)
        x1$ = "chainarraybuf" + x$
        x2$ = "chainarraybufsiz" + x$
        WriteBufLine GlobTxtBuf, "static uint8 *" + x1$ + "=(uint8*)malloc(1);"
        WriteBufLine GlobTxtBuf, "static int64 " + x2$ + "=0;"
        'read next command
        WriteBufLine MainTxtBuf, "sub_get(FF,NULL,byte_element((uint64)&int32val,4," + NewByteElement$ + "),0);"

        IF command = 3 THEN WriteBufLine MainTxtBuf, "if (int32val==3){" 'fixed-length-element array
        IF command = 4 THEN WriteBufLine MainTxtBuf, "if (int32val==4){" 'var-length-element array
        WriteBufLine MainTxtBuf, x2$ + "+=4; " + x1$ + "=(uint8*)realloc(" + x1$ + "," + x2$ + "); *(int32*)(" + x1$ + "+" + x2$ + "-4)=int32val;"

        IF command = 3 THEN
            'read size in bits of one element, convert it to bytes
            WriteBufLine MainTxtBuf, "sub_get(FF,NULL,byte_element((uint64)&int64val,8," + NewByteElement$ + "),0);"
            WriteBufLine MainTxtBuf, x2$ + "+=8; " + x1$ + "=(uint8*)realloc(" + x1$ + "," + x2$ + "); *(int64*)(" + x1$ + "+" + x2$ + "-8)=int64val;"
            WriteBufLine MainTxtBuf, "bytes=int64val>>3;"
        END IF 'com=3

        IF command = 4 THEN WriteBufLine MainTxtBuf, "bytes=1;" 'bytes used to calculate number of elements

        'read number of dimensions
        WriteBufLine MainTxtBuf, "sub_get(FF,NULL,byte_element((uint64)&int32val,4," + NewByteElement$ + "),0);"
        WriteBufLine MainTxtBuf, x2$ + "+=4; " + x1$ + "=(uint8*)realloc(" + x1$ + "," + x2$ + "); *(int32*)(" + x1$ + "+" + x2$ + "-4)=int32val;"

        'read size of dimensions & calculate the size of the array in bytes
        WriteBufLine MainTxtBuf, "while(int32val--){"
        WriteBufLine MainTxtBuf, "sub_get(FF,NULL,byte_element((uint64)&int64val,8," + NewByteElement$ + "),0);" 'lbound
        WriteBufLine MainTxtBuf, x2$ + "+=8; " + x1$ + "=(uint8*)realloc(" + x1$ + "," + x2$ + "); *(int64*)(" + x1$ + "+" + x2$ + "-8)=int64val;"
        WriteBufLine MainTxtBuf, "sub_get(FF,NULL,byte_element((uint64)&int64val2,8," + NewByteElement$ + "),0);" 'ubound
        WriteBufLine MainTxtBuf, x2$ + "+=8; " + x1$ + "=(uint8*)realloc(" + x1$ + "," + x2$ + "); *(int64*)(" + x1$ + "+" + x2$ + "-8)=int64val2;"
        WriteBufLine MainTxtBuf, "bytes*=(int64val2-int64val+1);"
        WriteBufLine MainTxtBuf, "}"

        IF command = 3 THEN
            'read the array data
            WriteBufLine MainTxtBuf, x2$ + "+=bytes; " + x1$ + "=(uint8*)realloc(" + x1$ + "," + x2$ + ");"
            WriteBufLine MainTxtBuf, "sub_get(FF,NULL,byte_element((uint64)(" + x1$ + "+" + x2$ + "-bytes),bytes," + NewByteElement$ + "),0);"
        END IF 'com=3

        IF command = 4 THEN
            WriteBufLine MainTxtBuf, "bytei=0;"
            WriteBufLine MainTxtBuf, "while(bytei<bytes){"
            WriteBufLine MainTxtBuf, "sub_get(FF,NULL,byte_element((uint64)&int64val,8," + NewByteElement$ + "),0);" 'get size
            WriteBufLine MainTxtBuf, x2$ + "+=8; " + x1$ + "=(uint8*)realloc(" + x1$ + "," + x2$ + "); *(int64*)(" + x1$ + "+" + x2$ + "-8)=int64val;"
            WriteBufLine MainTxtBuf, x2$ + "+=(int64val>>3); " + x1$ + "=(uint8*)realloc(" + x1$ + "," + x2$ + ");"
            WriteBufLine MainTxtBuf, "sub_get(FF,NULL,byte_element((uint64)(" + x1$ + "+" + x2$ + "-(int64val>>3)),(int64val>>3)," + NewByteElement$ + "),0);"
            WriteBufLine MainTxtBuf, "bytei++;"
            WriteBufLine MainTxtBuf, "}"
        END IF

        'get next command
        WriteBufLine MainTxtBuf, "sub_get(FF,NULL,byte_element((uint64)&int32val,4," + NewByteElement$ + "),0);"
        WriteBufLine MainTxtBuf, "}" 'command=3 or 4

        WriteBufLine MainTxtBuf, "}" 'array place-holder


        'save array (saves the buffered data, if any, for later)

        MainTxtBuf = OpenBuffer%("O", tmpdir$ + "chain" + _TOSTR$(i) + ".txt")
        WriteBufLine MainTxtBuf, "int32val=2;" 'placeholder
        WriteBufLine MainTxtBuf, "sub_put(FF,NULL,byte_element((uint64)&int32val,4," + NewByteElement$ + "),0);"

        WriteBufLine MainTxtBuf, "sub_put(FF,NULL,byte_element((uint64)" + x1$ + "," + x2$ + "," + NewByteElement$ + "),0);"




    ELSE
        'note: arrayelements<>-1

        'load array

        MainTxtBuf = OpenBuffer%("O", tmpdir$ + "inpchain" + _TOSTR$(i) + ".txt")

        WriteBufLine MainTxtBuf, "if (int32val==2){" 'array place-holder
        WriteBufLine MainTxtBuf, "sub_get(FF,NULL,byte_element((uint64)&int32val,4," + NewByteElement$ + "),0);"

        IF command = 3 THEN WriteBufLine MainTxtBuf, "if (int32val==3){" 'fixed-length-element array
        IF command = 4 THEN WriteBufLine MainTxtBuf, "if (int32val==4){" 'var-length-element array

        IF command = 3 THEN
            'get size in bits
            WriteBufLine MainTxtBuf, "sub_get(FF,NULL,byte_element((uint64)&int64val,8," + NewByteElement$ + "),0);"
            '***assume correct***
        END IF

        'get number of elements
        WriteBufLine MainTxtBuf, "sub_get(FF,NULL,byte_element((uint64)&int32val,4," + NewByteElement$ + "),0);"
        '***assume correct***

        e$ = ""
        IF command = 4 THEN WriteBufLine MainTxtBuf, "bytes=1;" 'bytes counts the number of total elements
        FOR x2 = 1 TO arrayelements

            'create 'secret' variables to assist in passing common arrays
            IF x2 > ncommontmp THEN
                ncommontmp = ncommontmp + 1

                IF Debug THEN PRINT #9, "Calling DIM2(...)..."
                IF Error_Happened THEN GOTO errmes
                retval = dim2("___RESERVED_COMMON_LBOUND" + _TOSTR$(ncommontmp), "_INTEGER64", 0, "")
                IF Error_Happened THEN GOTO errmes
                retval = dim2("___RESERVED_COMMON_UBOUND" + _TOSTR$(ncommontmp), "_INTEGER64", 0, "")
                IF Error_Happened THEN GOTO errmes
                IF Debug THEN PRINT #9, "Finished calling DIM2(...)!"
                IF Error_Happened THEN GOTO errmes


            END IF

            WriteBufLine MainTxtBuf, "sub_get(FF,NULL,byte_element((uint64)&int64val,8," + NewByteElement$ + "),0);"
            WriteBufLine MainTxtBuf, "*__INTEGER64____RESERVED_COMMON_LBOUND" + _TOSTR$(x2) + "=int64val;"
            WriteBufLine MainTxtBuf, "sub_get(FF,NULL,byte_element((uint64)&int64val2,8," + NewByteElement$ + "),0);"
            WriteBufLine MainTxtBuf, "*__INTEGER64____RESERVED_COMMON_UBOUND" + _TOSTR$(x2) + "=int64val2;"
            IF command = 4 THEN WriteBufLine MainTxtBuf, "bytes*=(int64val2-int64val+1);"
            IF x2 > 1 THEN e$ = e$ + sp + "," + sp
            e$ = e$ + "___RESERVED_COMMON_LBOUND" + _TOSTR$(x2) + sp + "TO" + sp + "___RESERVED_COMMON_UBOUND" + _TOSTR$(x2)
        NEXT

        IF Debug THEN PRINT #9, "Calling DIM2(" + purevarname$ + "," + typ$ + ",0," + e$ + ")..."
        IF Error_Happened THEN GOTO errmes
        'Note: purevarname$ is simply varname$ without the type symbol after it
        redimoption = 1
        retval = dim2(purevarname$, typ$, 0, e$)
        IF Error_Happened THEN GOTO errmes
        redimoption = 0
        IF Debug THEN PRINT #9, "Finished calling DIM2(" + purevarname$ + "," + typ$ + ",0," + e$ + ")!"
        IF Error_Happened THEN GOTO errmes

        IF command = 3 THEN
            'use get to load in the array data
            varname$ = varname$ + sp + "(" + sp + ")"
            e$ = evaluatetotyp(fixoperationorder$(varname$), -4)
            IF Error_Happened THEN GOTO errmes
            WriteBufLine MainTxtBuf, "sub_get(FF,NULL," + e$ + ",0);"
        END IF

        IF command = 4 THEN
            WriteBufLine MainTxtBuf, "bytei=0;"
            WriteBufLine MainTxtBuf, "while(bytei<bytes){"
            WriteBufLine MainTxtBuf, "sub_get(FF,NULL,byte_element((uint64)&int64val,8," + NewByteElement$ + "),0);" 'get size
            WriteBufLine MainTxtBuf, "tqbs=((qbs*)(((uint64*)(" + n2$ + "[0]))[bytei]));" 'get element
            WriteBufLine MainTxtBuf, "qbs_set(tqbs,qbs_new(int64val>>3,1));" 'change string size
            WriteBufLine MainTxtBuf, "sub_get(FF,NULL,byte_element((uint64)tqbs->chr,int64val>>3," + NewByteElement$ + "),0);" 'get size
            WriteBufLine MainTxtBuf, "bytei++;"
            WriteBufLine MainTxtBuf, "}"
        END IF

        'get next command
        WriteBufLine MainTxtBuf, "sub_get(FF,NULL,byte_element((uint64)&int32val,4," + NewByteElement$ + "),0);"
        WriteBufLine MainTxtBuf, "}"
        WriteBufLine MainTxtBuf, "}"

        'save array

        MainTxtBuf = OpenBuffer%("O", tmpdir$ + "chain" + _TOSTR$(i) + ".txt")

        WriteBufLine MainTxtBuf, "int32val=2;" 'placeholder
        WriteBufLine MainTxtBuf, "sub_put(FF,NULL,byte_element((uint64)&int32val,4," + NewByteElement$ + "),0);"

        WriteBufLine MainTxtBuf, "if (" + n2$ + "[2]&1){" 'don't add unless defined

        IF command = 3 THEN WriteBufLine MainTxtBuf, "int32val=3;"
        IF command = 4 THEN WriteBufLine MainTxtBuf, "int32val=4;"
        WriteBufLine MainTxtBuf, "sub_put(FF,NULL,byte_element((uint64)&int32val,4," + NewByteElement$ + "),0);"

        IF command = 3 THEN
            'size of each element in bits
            bits = t AND UDTMASK
            IF t AND ISUDT THEN bits = udtxsize(t AND UDTMASK)
            IF t AND ISSTRING THEN bits = tsize * 8
            WriteBufLine MainTxtBuf, "int64val=" + _TOSTR$(bits) + ";" 'size in bits
            WriteBufLine MainTxtBuf, "sub_put(FF,NULL,byte_element((uint64)&int64val,8," + NewByteElement$ + "),0);"
        END IF 'com=3

        WriteBufLine MainTxtBuf, "int32val=" + _TOSTR$(arrayelements) + ";" 'number of dimensions
        WriteBufLine MainTxtBuf, "sub_put(FF,NULL,byte_element((uint64)&int32val,4," + NewByteElement$ + "),0);"

        IF command = 3 THEN

            FOR x2 = 1 TO arrayelements
                'simulate calls to lbound/ubound
                e$ = "LBOUND" + sp + "(" + sp + n$ + sp + "," + sp + _TOSTR$(x2) + sp + ")"
                e$ = evaluatetotyp(fixoperationorder$(e$), 64)
                IF Error_Happened THEN GOTO errmes
                WriteBufLine MainTxtBuf, "int64val=" + e$ + ";"
                WriteBufLine MainTxtBuf, "sub_put(FF,NULL,byte_element((uint64)&int64val,8," + NewByteElement$ + "),0);"
                e$ = "UBOUND" + sp + "(" + sp + n$ + sp + "," + sp + _TOSTR$(x2) + sp + ")"
                e$ = evaluatetotyp(fixoperationorder$(e$), 64)
                IF Error_Happened THEN GOTO errmes
                WriteBufLine MainTxtBuf, "int64val=" + e$ + ";"
                WriteBufLine MainTxtBuf, "sub_put(FF,NULL,byte_element((uint64)&int64val,8," + NewByteElement$ + "),0);"
            NEXT

            'array data
            e$ = evaluatetotyp(fixoperationorder$(n$ + sp + "(" + sp + ")"), -4)
            IF Error_Happened THEN GOTO errmes
            WriteBufLine MainTxtBuf, "sub_put(FF,NULL," + e$ + ",0);"

        END IF 'com=3

        IF command = 4 THEN

            'store LBOUND/UBOUND values and calculate number of total elements/strings
            WriteBufLine MainTxtBuf, "bytes=1;" 'note: bytes is actually the total number of elements
            FOR x2 = 1 TO arrayelements
                e$ = "LBOUND" + sp + "(" + sp + n$ + sp + "," + sp + _TOSTR$(x2) + sp + ")"
                e$ = evaluatetotyp(fixoperationorder$(e$), 64)
                IF Error_Happened THEN GOTO errmes
                WriteBufLine MainTxtBuf, "int64val=" + e$ + ";"
                WriteBufLine MainTxtBuf, "sub_put(FF,NULL,byte_element((uint64)&int64val,8," + NewByteElement$ + "),0);"
                e$ = "UBOUND" + sp + "(" + sp + n$ + sp + "," + sp + _TOSTR$(x2) + sp + ")"
                e$ = evaluatetotyp(fixoperationorder$(e$), 64)
                IF Error_Happened THEN GOTO errmes
                WriteBufLine MainTxtBuf, "int64val2=" + e$ + ";"
                WriteBufLine MainTxtBuf, "sub_put(FF,NULL,byte_element((uint64)&int64val2,8," + NewByteElement$ + "),0);"
                WriteBufLine MainTxtBuf, "bytes*=(int64val2-int64val+1);"
            NEXT

            WriteBufLine MainTxtBuf, "bytei=0;"
            WriteBufLine MainTxtBuf, "while(bytei<bytes){"
            WriteBufLine MainTxtBuf, "tqbs=((qbs*)(((uint64*)(" + n2$ + "[0]))[bytei]));" 'get element
            WriteBufLine MainTxtBuf, "int64val=tqbs->len; int64val<<=3;"
            WriteBufLine MainTxtBuf, "sub_put(FF,NULL,byte_element((uint64)&int64val,8," + NewByteElement$ + "),0);" 'size of element
            WriteBufLine MainTxtBuf, "sub_put(FF,NULL,byte_element((uint64)tqbs->chr,tqbs->len," + NewByteElement$ + "),0);" 'element data
            WriteBufLine MainTxtBuf, "bytei++;"
            WriteBufLine MainTxtBuf, "}"

        END IF 'com=4

        WriteBufLine MainTxtBuf, "}" 'don't add unless defined



    END IF 'id.arrayelements=-1

NEXT
use_global_byte_elements = 0
IF Debug THEN PRINT #9, "Finished generation of code for saving/sharing common array data!"


FOR closeall = 1 TO 300: CLOSE closeall: NEXT
OPEN tmpdir$ + "temp.bin" FOR OUTPUT LOCK WRITE AS #26 'relock

compilelog$ = tmpdir$ + "compilelog.txt"

OPEN compilelog$ FOR OUTPUT AS #1: CLOSE #1 'Clear log

IF idemode = 0 AND NOT QuietMode THEN
    IF ConsoleMode THEN
        PRINT "[" + STRING$(maxprogresswidth, ".") + "] 100%"
    ELSE
        LOCATE , 1
        PRINT STRING$(maxprogresswidth, 219) + " 100%"
    END IF
END IF

IF NOT IgnoreWarnings THEN
    totalUnusedVariables = 0
    FOR i = 1 TO totalVariablesCreated
        IF usedVariableList(i).used = 0 THEN
            totalUnusedVariables = totalUnusedVariables + 1
        END IF
    NEXT

    IF totalUnusedVariables > 0 THEN
        maxVarNameLen = 0
        FOR i = 1 TO totalVariablesCreated
            IF usedVariableList(i).used = 0 THEN
                IF LEN(usedVariableList(i).name) > maxVarNameLen THEN maxVarNameLen = LEN(usedVariableList(i).name)
            END IF
        NEXT

        header$ = "Unused variable"
        FOR i = 1 TO totalVariablesCreated
            IF usedVariableList(i).used = 0 THEN
                addWarning usedVariableList(i).linenumber, usedVariableList(i).includeLevel, usedVariableList(i).includedLine, usedVariableList(i).includedFile, header$, usedVariableList(i).name + SPACE$((maxVarNameLen + 1) - LEN(usedVariableList(i).name)) + "  " + usedVariableList(i).varType
            END IF
        NEXT
    END IF
END IF

IF idemode THEN GOTO ideret5
ide6:

IF idemode = 0 AND NOT NoCCompileMode THEN
    IF NOT QuietMode THEN
        PRINT
        IF os$ = "LNX" THEN
            PRINT "Compiling C++ code into executable..."
        ELSE
            PRINT "Compiling C++ code into EXE..."
        END IF
    END IF

    ' Fixup the output path if we got an `-o` argument
    IF LEN(CMDLineOutFile$) > 0 THEN
        IF LEN(CMDLineOutFile$) THEN
            'resolve relative path for output file
            path.out$ = getfilepath$(CMDLineOutFile$)
            f$ = MID$(CMDLineOutFile$, LEN(path.out$) + 1)

            IF UCASE$(GetFileExtension$(f$)) = "EXE" THEN
                file$ = RemoveFileExtension$(f$)
            ELSE
                file$ = f$
            END IF
        END IF

        IF LEN(path.out$) > 0 THEN
            currentdir$ = _CWD$

            IF _DIREXISTS(path.out$) = 0 THEN
                PRINT
                PRINT "Can't create output executable - path not found: " + path.out$
                IF ConsoleMode THEN SYSTEM 1
                END 1
            END IF

            CHDIR path.out$
            path.out$ = _CWD$
            CHDIR currentdir$

            IF RIGHT$(path.out$, 1) <> pathsep$ THEN path.out$ = path.out$ + pathsep$
            path.exe$ = path.out$

            SaveExeWithSource = _TRUE 'Override the global setting if an output file was specified
        END IF
    END IF
    t.path.exe$ = path.exe$
    IF _FILEEXISTS(path.exe$ + file$ + extension$) THEN
        E = 0
        ON ERROR GOTO qberror_test
        KILL path.exe$ + file$ + extension$
        ON ERROR GOTO qberror
        IF E = 1 THEN
            a$ = "CANNOT CREATE " + CHR$(34) + file$ + extension$ + CHR$(34) + " BECAUSE THE FILE IS ALREADY IN USE!": GOTO errmes
        END IF
    END IF
    path.exe$ = t.path.exe$
END IF

IF ExeIconSet <> 0 THEN 'ExeIconSet is not boolean, but a line number
    linenumber = ExeIconSet 'on error, this allows reporting the linenumber where $EXEICON was used
    wholeline = " $EXEICON:'" + ExeIconFile$ + "'"

    ' Copy icon file into temp directory with known name
    ' This solves the problem of the resource file needing an absolute path
    fail = CopyFile&(ExeIconFile$, tmpdir$ + "icon.ico")
    IF fail THEN a$ = "Error copying " + QuotedFilename$(ExeIconFile$) + " to temp directory": GOTO errmes
END IF

IF VersionInfoSet THEN
    ManiBuf = OpenBuffer%("O", tmpdir$ + file$ + extension$ + ".manifest")
    WriteBufLine ManiBuf, "<?xml version=" + AddQuotes$("1.0") + " encoding=" + AddQuotes$("UTF-8") + " standalone=" + AddQuotes$("yes") + "?>"
    WriteBufLine ManiBuf, "<assembly xmlns=" + AddQuotes$("urn:schemas-microsoft-com:asm.v1") + " manifestVersion=" + AddQuotes$("1.0") + ">"
    WriteBufLine ManiBuf, "<assemblyIdentity"
    WriteBufLine ManiBuf, "    version=" + AddQuotes$("1.0.0.0")
    WriteBufLine ManiBuf, "    processorArchitecture=" + AddQuotes$("*")
    WriteBufLine ManiBuf, "    name=" + AddQuotes$(viCompanyName$ + "." + viProductName$ + "." + viProductName$)
    WriteBufLine ManiBuf, "    type=" + AddQuotes$("win32")
    WriteBufLine ManiBuf, "/>"
    WriteBufLine ManiBuf, "<description>" + viFileDescription$ + "</description>"
    WriteBufLine ManiBuf, "<dependency>"
    WriteBufLine ManiBuf, "    <dependentAssembly>"
    WriteBufLine ManiBuf, "        <assemblyIdentity"
    WriteBufLine ManiBuf, "            type=" + AddQuotes$("win32")
    WriteBufLine ManiBuf, "            name=" + AddQuotes$("Microsoft.Windows.Common-Controls")
    WriteBufLine ManiBuf, "            version=" + AddQuotes$("6.0.0.0")
    WriteBufLine ManiBuf, "            processorArchitecture=" + AddQuotes$("*")
    WriteBufLine ManiBuf, "            publicKeyToken=" + AddQuotes$("6595b64144ccf1df")
    WriteBufLine ManiBuf, "            language=" + AddQuotes$("*")
    WriteBufLine ManiBuf, "        />"
    WriteBufLine ManiBuf, "    </dependentAssembly>"
    WriteBufLine ManiBuf, "</dependency>"
    WriteBufLine ManiBuf, "</assembly>"

    ManiBuf = OpenBuffer%("O", tmpdir$ + "manifest.h")
    WriteBufLine ManiBuf, "#ifndef RESOURCE_H"
    WriteBufLine ManiBuf, "#define   RESOURCE_H"
    WriteBufLine ManiBuf, "#ifdef    __cplusplus"
    WriteBufLine ManiBuf, "extern " + AddQuotes$("C") + " {"
    WriteBufLine ManiBuf, "#endif"
    WriteBufLine ManiBuf, "#ifdef    __cplusplus"
    WriteBufLine ManiBuf, "}"
    WriteBufLine ManiBuf, "#endif"
    WriteBufLine ManiBuf, "#endif    /* RESOURCE_H */"
    WriteBufLine ManiBuf, "#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1 /*Defined manifest file*/"
    WriteBufLine ManiBuf, "#define RT_MANIFEST                       24"
END IF

IF VersionInfoSet OR ExeIconSet <> 0 THEN 'ExeIconSet is not boolean, but a line number
    IconRcBuf = OpenBuffer%("O", tmpdir$ + "icon.rc")

    IF ExeIconSet <> 0 THEN 'ExeIconSet is not boolean, but a line number
        WriteBufLine IconRcBuf, "0 ICON " + AddQuotes$("icon.ico")
    END IF

    IF VersionInfoSet THEN
        WriteBufLine IconRcBuf, ""
        WriteBufLine IconRcBuf, "#include " + AddQuotes$("manifest.h")
        WriteBufLine IconRcBuf, ""
        WriteBufLine IconRcBuf, "CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST " + AddQuotes$(file$ + extension$ + ".manifest")
        WriteBufLine IconRcBuf, ""
        WriteBufLine IconRcBuf, "1 VERSIONINFO"
        IF LEN(viFileVersionNum$) THEN WriteBufLine IconRcBuf, "FILEVERSION     " + viFileVersionNum$
        IF LEN(viProductVersionNum$) THEN WriteBufLine IconRcBuf, "PRODUCTVERSION  " + viProductVersionNum$
        WriteBufLine IconRcBuf, "BEGIN"
        WriteBufLine IconRcBuf, "    BLOCK " + AddQuotes$("StringFileInfo")
        WriteBufLine IconRcBuf, "    BEGIN"
        WriteBufLine IconRcBuf, "        BLOCK " + AddQuotes$("040904E4")
        WriteBufLine IconRcBuf, "        BEGIN"
        WriteBufLine IconRcBuf, "            VALUE " + AddQuotes$("CompanyName") + "," + AddQuotes$(viCompanyName$ + "\0")
        WriteBufLine IconRcBuf, "            VALUE " + AddQuotes$("FileDescription") + "," + AddQuotes$(viFileDescription$ + "\0")
        WriteBufLine IconRcBuf, "            VALUE " + AddQuotes$("FileVersion") + "," + AddQuotes$(viFileVersion$ + "\0")
        WriteBufLine IconRcBuf, "            VALUE " + AddQuotes$("InternalName") + "," + AddQuotes$(viInternalName$ + "\0")
        WriteBufLine IconRcBuf, "            VALUE " + AddQuotes$("LegalCopyright") + "," + AddQuotes$(viLegalCopyright$ + "\0")
        WriteBufLine IconRcBuf, "            VALUE " + AddQuotes$("LegalTrademarks") + "," + AddQuotes$(viLegalTrademarks$ + "\0")
        WriteBufLine IconRcBuf, "            VALUE " + AddQuotes$("OriginalFilename") + "," + AddQuotes$(viOriginalFilename$ + "\0")
        WriteBufLine IconRcBuf, "            VALUE " + AddQuotes$("ProductName") + "," + AddQuotes$(viProductName$ + "\0")
        WriteBufLine IconRcBuf, "            VALUE " + AddQuotes$("ProductVersion") + "," + AddQuotes$(viProductVersion$ + "\0")
        WriteBufLine IconRcBuf, "            VALUE " + AddQuotes$("Comments") + "," + AddQuotes$(viComments$ + "\0")
        WriteBufLine IconRcBuf, "            VALUE " + AddQuotes$("Web") + "," + AddQuotes$(viWeb$ + "\0")
        WriteBufLine IconRcBuf, "        END"
        WriteBufLine IconRcBuf, "    END"
        WriteBufLine IconRcBuf, "    BLOCK " + AddQuotes$("VarFileInfo")
        WriteBufLine IconRcBuf, "    BEGIN"
        WriteBufLine IconRcBuf, "            VALUE " + AddQuotes$("Translation") + ", 0x409, 0x04E4"
        WriteBufLine IconRcBuf, "    END"
        WriteBufLine IconRcBuf, "END"
    END IF
END IF

'Write out all buffered files, all remaining
'actions are performed on the disk based files
WriteBuffers ""

IF FormatMode THEN
    'Move temp file to final location
    fail = CopyFile&(tmpdir$ + "format.out", path.exe$ + file$)
    IF fail THEN a$ = "Error saving formatted output to " + path.exe$ + file$: GOTO errmes
    GOTO NoCCompile
END IF

'=== BEGIN: embedding files ===
eflFF = FREEFILE
OPEN "O", #eflFF, tmpdir$ + "embedded.cpp"
'write required header stuff
PRINT #eflFF, "#include <stdint.h>"
PRINT #eflFF, "#include <string.h>"
PRINT #eflFF, "#include "; AddQuotes$("../c/libqb.h")
PRINT #eflFF, "#include "; AddQuotes$("../c/libqb/include/compression.h")
PRINT #eflFF, ""
CLOSE #eflFF
'append files converted into arrays
'> embed only those $EMBED files, which are referenced by at least
'  one _EMBEDDED$() call to avoid unnecessary bloat
'> adjust dependency settings according to the process
eflUB = UBOUND(embedFileList$, 2)
FOR i = 0 TO eflUB
    IF embedFileList$(eflFile, i) <> "" AND embedFileList$(eflUsed, i) = "yes" THEN
        IF ConvertFileToCArray%(embedFileList$(eflFile, i), embedFileList$(eflHand, i)) THEN
            SetDependency DEPENDENCY_ZLIB
        END IF
        SetDependency DEPENDENCY_EMBED
    END IF
NEXT i
'-----
eflFF = FREEFILE
OPEN "A", #eflFF, tmpdir$ + "embedded.cpp"
'append the internal retrieval function for _EMBEDDED$()
PRINT #eflFF, "qbs *func__embedded(qbs *handle)"
PRINT #eflFF, "{"
FOR i = 0 TO eflUB
    IF embedFileList$(eflFile, i) <> "" AND embedFileList$(eflUsed, i) = "yes" THEN
        PRINT #eflFF, "    if (qbs_equal(handle, qbs_new_txt("; AddQuotes$(embedFileList$(eflHand, i)); "))) {return GetArrayData_"; embedFileList$(eflHand, i); "();}"
    END IF
NEXT i
PRINT #eflFF, "    return qbs_new_txt("; MKI$(&H2222); ");"
PRINT #eflFF, "}"
PRINT #eflFF, ""
CLOSE #eflFF
'=== END: embedding files ===

'Update dependencies

o$ = LCASE$(os$)
win = 0: IF os$ = "WIN" THEN win = 1
lnx = 0: IF os$ = "LNX" THEN lnx = 1
mac = 0: IF MacOSX THEN mac = 1: o$ = "osx"
ver$ = Version$ 'eg. "0.123"
libs$ = ""
makedeps$ = ""

localpath$ = "internal\c\"


IF DEPENDENCY(DEPENDENCY_GL) THEN makedeps$ = makedeps$ + " DEP_GL=y"
IF DEPENDENCY(DEPENDENCY_IMAGE_CODEC) THEN makedeps$ = makedeps$ + " DEP_IMAGE_CODEC=y"
IF DEPENDENCY(DEPENDENCY_CONSOLE_ONLY) THEN makedeps$ = makedeps$ + " DEP_CONSOLE_ONLY=y"
IF DEPENDENCY(DEPENDENCY_SOCKETS) THEN makedeps$ = makedeps$ + " DEP_SOCKETS=y DEP_HTTP=y"
IF DEPENDENCY(DEPENDENCY_PRINTER) THEN makedeps$ = makedeps$ + " DEP_PRINTER=y"
IF DEPENDENCY(DEPENDENCY_ICON) THEN makedeps$ = makedeps$ + " DEP_ICON=y"
IF DEPENDENCY(DEPENDENCY_SCREENIMAGE) THEN makedeps$ = makedeps$ + " DEP_SCREENIMAGE=y"
IF DEPENDENCY(DEPENDENCY_LOADFONT) THEN makedeps$ = makedeps$ + " DEP_FONT=y"
IF DEPENDENCY(DEPENDENCY_DEVICEINPUT) THEN makedeps$ = makedeps$ + " DEP_DEVICEINPUT=y"
IF DEPENDENCY(DEPENDENCY_ZLIB) THEN makedeps$ = makedeps$ + " DEP_ZLIB=y"
IF DEPENDENCY(DEPENDENCY_EMBED) THEN makedeps$ = makedeps$ + " DEP_EMBED=y"
IF GetRCStateVar(ConsoleOn) THEN makedeps$ = makedeps$ + " DEP_CONSOLE=y"
'ExeIconSet is not boolean, but a line number
IF ExeIconSet <> 0 OR VersionInfoSet THEN makedeps$ = makedeps$ + " DEP_ICON_RC=y"

IF DEPENDENCY(DEPENDENCY_MINIAUDIO) THEN makedeps$ = makedeps$ + " DEP_AUDIO_MINIAUDIO=y"

IF tempfolderindex > 1 THEN makedeps$ = makedeps$ + " TEMP_ID=" + _TOSTR$(tempfolderindex)

CxxFlagsExtra$ = ExtraCppFlags$
CxxLibsExtra$ = ExtraLinkerFlags$

' If debugging then use `-Og` rather than `-O2`
IF OptimizeCppProgram THEN
    IF IncludeDebugInfo THEN
        CxxFlagsExtra$ = CxxFlagsExtra$ + " -Og"
    ELSE
        CxxFlagsExtra$ = CxxFlagsExtra$ + " -O2"
    END IF
ELSE
    IF IncludeDebugInfo THEN
        CxxFlagsExtra$ = CxxFlagsExtra$ + " -g"
    END IF
END IF

CxxLibsExtra$ = CxxLibsExtra$ + " " + mylib$ + " " + mylibopt$

' Make and the shell don't like certain characters in the file name, so we
' escape them to get them to handle them properly
escapedExe$ = path.exe$ + file$ + extension$

' Make escaping
escapedExe$ = StrReplace$(escapedExe$, _CHR_QUOTE, "\" + _CHR_QUOTE)
escapedExe$ = StrReplace$(escapedExe$, "$", "$$")

IF os$ = "LNX" THEN
    ' sh escaping
    escapedExe$ = StrReplace$(escapedExe$, "'", "'\''")
    escapedExe$ = "'" + escapedExe$ + "'"
ELSE
    escapedExe$ = _CHR_QUOTE + escapedExe$ + _CHR_QUOTE
END IF

makeline$ = GetMakeExecutable$ + makedeps$ + " EXE=" + escapedExe$
makeline$ = makeline$ + " " + AddQuotes$("CXXFLAGS_EXTRA=" + CxxFlagsExtra$)
makeline$ = makeline$ + " " + AddQuotes$("CFLAGS_EXTRA=" + CxxFlagsExtra$)
makeline$ = makeline$ + " " + AddQuotes$("CXXLIBS_EXTRA=" + CxxLibsExtra$)
makeline$ = makeline$ + " -j" + AddQuotes$(_TOSTR$(MaxParallelProcesses))

IF NOT StripDebugSymbols THEN
    makeline$ = makeline$ + " STRIP_SYMBOLS=n"
END IF

' We avoid generating the license file if the user picked the "No Exe" option
IF GenerateLicenseFile AND NOT NoExeSaved THEN
    makeline$ = makeline$ + " GENERATE_LICENSE=y"
END IF

'Clear nm output from previous runs
FOR x = 1 TO ResolveStaticFunctions
    IF LEN(ResolveStaticFunction_File(x)) THEN
        s$ = MakeNMOutputFilename$(ResolveStaticFunction_File(x), 0)
        IF _FILEEXISTS(s$) THEN KILL s$: ClearBuffers s$

        s$ = MakeNMOutputFilename$(ResolveStaticFunction_File(x), 1)
        IF _FILEEXISTS(s$) THEN KILL s$: ClearBuffers s$
    END IF
NEXT x

' Delete existing qbx.o file, it ensures that it always gets rebuilt
ON ERROR GOTO qberror_test
IF tempfolderindex > 1 THEN
    KILL "internal/c/qbx" + _TOSTR$(tempfolderindex) + ".o"
ELSE
    KILL "internal/c/qbx.o"
END IF
ON ERROR GOTO qberror

IF os$ = "WIN" THEN

    IF UseSystemMinGW THEN
        makeline$ = makeline$ + " " + AddQuotes$("USE_SYSTEM_MINGW=y")
    END IF

    makeline$ = makeline$ + " OS=win"

    'resolve static function definitions and add to global.txt
    FOR x = 1 TO ResolveStaticFunctions
        nm_output_file$ = MakeNMOutputFilename$(ResolveStaticFunction_File(x), 0)
        nm_output_file_dynamic$ = MakeNMOutputFilename$(ResolveStaticFunction_File(x), 1)
        IF LEN(ResolveStaticFunction_File(x)) THEN

            n = 0
            IF NOT _FILEEXISTS(nm_output_file$) THEN
                SHELL _HIDE "cmd /c " + GetCompilerPath$ + "nm.exe " + AddQuotes$(ResolveStaticFunction_File(x)) + " --demangle -g >" + AddQuotes$(nm_output_file$)
            END IF
            s$ = " " + ResolveStaticFunction_Name(x) + "("
            fh = OpenBuffer%("I", nm_output_file$)
            DO UNTIL EndOfBuf%(fh)
                a$ = ReadBufLine$(fh)
                IF LEN(a$) THEN
                    'search for SPACE+functionname+LEFTBRACKET
                    x1 = INSTR(a$, s$)
                    IF x1 THEN
                        IF ResolveStaticFunction_Method(x) = 1 THEN
                            x1 = x1 + 1
                            x2 = INSTR(x1, a$, ")")
                            fh2 = FREEFILE
                            OPEN tmpdir$ + "global.txt" FOR APPEND AS #fh2
                            PRINT #fh2, "extern void " + MID$(a$, x1, x2 - x1 + 1) + ";"
                            CLOSE #fh2
                        END IF
                        n = n + 1
                    END IF 'x1
                END IF '<>""
            LOOP
            IF n > 1 THEN a$ = "Unable to resolve multiple instances of sub/function '" + ResolveStaticFunction_Name(x) + "' in '" + ResolveStaticFunction_File(x) + "'": GOTO errmes

            IF n = 0 THEN 'attempt to locate simple function name without brackets
                s$ = ResolveStaticFunction_Name(x)
                fh = OpenBuffer%("I", nm_output_file$)
                DO UNTIL EndOfBuf%(fh)
                    a$ = ReadBufLine$(fh)
                    IF LEN(a$) THEN
                        'search for SPACE+functionname
                        ' clang's nm outputs LF line endings
                        IF OS_BITS = 32 THEN
                            ' On 32-bit Windows function names are decorated by a leading underscore
                            ' gcc's nm hides the leading underscore in the output, whereas clang's nm does not
                            x1 = (RIGHT$(a$, LEN(s$) + 1) = " " + s$) _ORELSE (RIGHT$(a$, LEN(s$) + 2) = " _" + s$)
                        ELSE
                            x1 = (RIGHT$(a$, LEN(s$) + 1) = " " + s$)
                        END IF
                        IF x1 THEN
                            fh2 = FREEFILE
                            IF ResolveStaticFunction_Method(x) = 1 THEN
                                OPEN tmpdir$ + "global.txt" FOR APPEND AS #fh2
                                PRINT #fh2, "extern " + CHR$(34) + "C" + CHR$(34) + "{"
                                PRINT #fh2, "extern void " + s$ + "(void);"
                                PRINT #fh2, "}"
                            ELSE
                                OPEN tmpdir$ + "externtype" + _TOSTR$(x) + ".txt" FOR OUTPUT AS #fh2
                                PRINT #fh2, "extern " + CHR$(34) + "C" + CHR$(34) + " "
                            END IF
                            CLOSE #fh2
                            n = n + 1
                            EXIT DO
                        END IF 'x1
                    END IF '<>""
                LOOP
            END IF

            IF n = 0 THEN 'a C++ dynamic object library?
                IF NOT _FILEEXISTS(nm_output_file_dynamic$) THEN
                    SHELL _HIDE "cmd /c " + GetCompilerPath$ + "nm.exe " + AddQuotes$(ResolveStaticFunction_File(x)) + " -D --demangle -g >" + AddQuotes$(nm_output_file_dynamic$)
                END IF
                s$ = " " + ResolveStaticFunction_Name(x) + "("
                fh = OpenBuffer%("I", nm_output_file$)
                DO UNTIL EndOfBuf%(fh)
                    a$ = ReadBufLine$(fh)
                    IF LEN(a$) THEN
                        'search for SPACE+functionname+LEFTBRACKET
                        x1 = INSTR(a$, s$)
                        IF x1 THEN
                            IF ResolveStaticFunction_Method(x) = 1 THEN
                                x1 = x1 + 1
                                x2 = INSTR(x1, a$, ")")
                                fh2 = FREEFILE
                                OPEN tmpdir$ + "global.txt" FOR APPEND AS #fh2
                                PRINT #fh2, "extern void " + MID$(a$, x1, x2 - x1 + 1) + ";"
                                CLOSE #fh2
                            END IF
                            n = n + 1
                        END IF 'x1
                    END IF '<>""
                LOOP
                IF n > 1 THEN a$ = "Unable to resolve multiple instances of sub/function '" + ResolveStaticFunction_Name(x) + "' in '" + ResolveStaticFunction_File(x) + "'": GOTO errmes
            END IF

            IF n = 0 THEN 'a C dynamic object library?
                s$ = ResolveStaticFunction_Name(x)
                fh = OpenBuffer%("I", nm_output_file_dynamic$)
                DO UNTIL EndOfBuf%(fh)
                    a$ = ReadBufLine$(fh)
                    IF LEN(a$) THEN
                        'search for SPACE+functionname
                        ' clang's nm outputs LF line endings
                        IF OS_BITS = 32 THEN
                            ' On 32-bit Windows function names are decorated by a leading underscore
                            ' gcc's nm hides the leading underscore in the output, whereas clang's nm does not
                            x1 = (RIGHT$(a$, LEN(s$) + 1) = " " + s$) _ORELSE (RIGHT$(a$, LEN(s$) + 2) = " _" + s$)
                        ELSE
                            x1 = (RIGHT$(a$, LEN(s$) + 1) = " " + s$)
                        END IF
                        IF x1 THEN
                            fh2 = FREEFILE
                            IF ResolveStaticFunction_Method(x) = 1 THEN
                                OPEN tmpdir$ + "global.txt" FOR APPEND AS #fh2
                                PRINT #fh2, "extern " + CHR$(34) + "C" + CHR$(34) + "{"
                                PRINT #fh2, "extern void " + s$ + "(void);"
                                PRINT #fh2, "}"
                            ELSE
                                OPEN tmpdir$ + "externtype" + _TOSTR$(x) + ".txt" FOR OUTPUT AS #fh2
                                PRINT #fh2, "extern " + CHR$(34) + "C" + CHR$(34) + " "
                            END IF
                            CLOSE #fh2
                            n = n + 1
                            EXIT DO
                        END IF 'x1
                    END IF '<>""
                LOOP
                IF n = 0 THEN a$ = "Could not find sub/function '" + ResolveStaticFunction_Name(x) + "' in '" + ResolveStaticFunction_File(x) + "'": GOTO errmes
            END IF

        END IF
    NEXT

    IF NOT NoCCompileMode THEN
        SHELL _HIDE "cmd /c " + makeline$ + " 1>> " + compilelog$ + " 2>&1"

        IF idemode THEN
            'Restore fg/bg colors
            dummy = DarkenFGBG(0)
        END IF
    END IF

    ffh = FREEFILE
    OPEN tmpdir$ + "debug_win.bat" FOR OUTPUT AS #ffh
    PRINT #ffh, "@echo off"
    PRINT #ffh, "cd %0\..\"
    PRINT #ffh, "cd ../.."
    PRINT #ffh, "echo C++ Debugging: " + file$ + extension$ + " using lldb.exe"
    PRINT #ffh, "echo Debugger commands:"
    PRINT #ffh, "echo After the debugger launches type 'run' to start your program"
    PRINT #ffh, "echo After your program crashes type 'list' to find where the problem is and fix/report it"
    PRINT #ffh, "echo Type 'quit' to exit"
    PRINT #ffh, "echo (the LLDB debugger has many other useful commands, this advice is for beginners)"
    PRINT #ffh, "pause"
    PRINT #ffh, GetCompilerPath$ + "lldb.exe " + CHR$(34) + path.exe$ + file$ + extension$ + CHR$(34)
    PRINT #ffh, "pause"
    CLOSE ffh
END IF

IF os$ = "LNX" THEN

    IF INSTR(_OS$, "[MACOSX]") THEN
        makeline$ = makeline$ + " OS=osx"
    ELSE
        makeline$ = makeline$ + " OS=lnx"
    END IF

    FOR x = 1 TO ResolveStaticFunctions
        nm_output_file$ = MakeNMOutputFilename$(ResolveStaticFunction_File(x), 0)
        nm_output_file_dynamic$ = MakeNMOutputFilename$(ResolveStaticFunction_File(x), 1)
        IF LEN(ResolveStaticFunction_File(x)) THEN

            n = 0
            IF NOT _FILEEXISTS(nm_output_file$) THEN
                IF MacOSX = 0 THEN SHELL _HIDE "nm " + AddQuotes$(ResolveStaticFunction_File(x)) + " --demangle -g >" + AddQuotes$(nm_output_file$) + " 2>" + AddQuotes$(tmpdir$ + "nm_error.txt")
                IF MacOSX THEN SHELL _HIDE "nm " + AddQuotes$(ResolveStaticFunction_File(x)) + " >" + AddQuotes$(nm_output_file$) + " 2>" + AddQuotes$(tmpdir$ + "nm_error.txt")
            END IF

            IF MacOSX = 0 THEN 'C++ name demangling not supported in MacOSX
                s$ = " " + ResolveStaticFunction_Name(x) + "("
                fh = OpenBuffer%("I", nm_output_file$)
                DO UNTIL EndOfBuf%(fh)
                    a$ = ReadBufLine$(fh)
                    IF LEN(a$) THEN
                        'search for SPACE+functionname+LEFTBRACKET
                        x1 = INSTR(a$, s$)
                        IF x1 THEN
                            IF ResolveStaticFunction_Method(x) = 1 THEN
                                x1 = x1 + 1
                                x2 = INSTR(x1, a$, ")")
                                fh2 = FREEFILE
                                OPEN tmpdir$ + "global.txt" FOR APPEND AS #fh2
                                PRINT #fh2, "extern void " + MID$(a$, x1, x2 - x1 + 1) + ";"
                                CLOSE #fh2
                            END IF
                            n = n + 1
                        END IF 'x1
                    END IF '<>""
                LOOP
                IF n > 1 THEN a$ = "Unable to resolve multiple instances of sub/function '" + ResolveStaticFunction_Name(x) + "' in '" + ResolveStaticFunction_File(x) + "'": GOTO errmes
            END IF 'macosx=0

            IF n = 0 THEN 'attempt to locate simple function name without brackets
                s$ = " " + ResolveStaticFunction_Name(x): s2$ = s$
                IF MacOSX THEN s$ = " _" + ResolveStaticFunction_Name(x) 'search for C mangled name
                fh = OpenBuffer%("I", nm_output_file$)
                DO UNTIL EndOfBuf%(fh)
                    a$ = ReadBufLine$(fh)
                    IF LEN(a$) THEN
                        'search for SPACE+functionname
                        x1 = INSTR(a$, s$)
                        IF RIGHT$(a$, LEN(s$)) = s$ THEN
                            fh2 = FREEFILE
                            IF ResolveStaticFunction_Method(x) = 1 THEN
                                OPEN tmpdir$ + "global.txt" FOR APPEND AS #fh2
                                PRINT #fh2, "extern " + CHR$(34) + "C" + CHR$(34) + "{"
                                PRINT #fh2, "extern void " + s2$ + "(void);"
                                PRINT #fh2, "}"
                            ELSE
                                OPEN tmpdir$ + "externtype" + _TOSTR$(x) + ".txt" FOR OUTPUT AS #fh2
                                PRINT #fh2, "extern " + CHR$(34) + "C" + CHR$(34) + " "
                            END IF
                            CLOSE #fh2
                            n = n + 1
                            EXIT DO
                        END IF 'x1
                    END IF '<>""
                LOOP
            END IF

            IF n = 0 THEN 'a C++ dynamic object library?
                IF MacOSX THEN GOTO macosx_libfind_failed
                IF NOT _FILEEXISTS(nm_output_file_dynamic$) THEN
                    SHELL _HIDE "nm " + AddQuotes$(ResolveStaticFunction_File(x)) + " -D --demangle -g >" + AddQuotes$(nm_output_file_dynamic$) + " 2>" + AddQuotes$(tmpdir$ + "nm_error.txt")
                END IF
                s$ = " " + ResolveStaticFunction_Name(x) + "("
                fh = OpenBuffer%("I", nm_output_file$)
                DO UNTIL EndOfBuf%(fh)
                    a$ = ReadBufLine$(fh)
                    IF LEN(a$) THEN
                        'search for SPACE+functionname+LEFTBRACKET
                        x1 = INSTR(a$, s$)
                        IF x1 THEN
                            IF ResolveStaticFunction_Method(x) = 1 THEN
                                x1 = x1 + 1
                                x2 = INSTR(x1, a$, ")")
                                fh2 = FREEFILE
                                OPEN tmpdir$ + "global.txt" FOR APPEND AS #fh2
                                PRINT #fh2, "extern void " + MID$(a$, x1, x2 - x1 + 1) + ";"
                                CLOSE #fh2
                            END IF
                            n = n + 1
                        END IF 'x1
                    END IF '<>""
                LOOP
                IF n > 1 THEN a$ = "Unable to resolve multiple instances of sub/function '" + ResolveStaticFunction_Name(x) + "' in '" + ResolveStaticFunction_File(x) + "'": GOTO errmes
            END IF

            IF n = 0 THEN 'a C dynamic object library?
                s$ = " " + ResolveStaticFunction_Name(x)
                fh = OpenBuffer%("I", nm_output_file_dynamic$)
                DO UNTIL EndOfBuf%(fh)
                    a$ = ReadBufLine$(fh)
                    IF LEN(a$) THEN
                        'search for SPACE+functionname
                        x1 = INSTR(a$, s$)
                        IF RIGHT$(a$, LEN(s$)) = s$ THEN
                            fh2 = FREEFILE
                            IF ResolveStaticFunction_Method(x) = 1 THEN
                                OPEN tmpdir$ + "global.txt" FOR APPEND AS #fh2
                                PRINT #fh2, "extern " + CHR$(34) + "C" + CHR$(34) + "{"
                                PRINT #fh2, "extern void " + s$ + "(void);"
                                PRINT #fh2, "}"
                            ELSE
                                OPEN tmpdir$ + "externtype" + _TOSTR$(x) + ".txt" FOR OUTPUT AS #fh2
                                PRINT #fh2, "extern " + CHR$(34) + "C" + CHR$(34) + " "
                            END IF
                            CLOSE #fh2
                            n = n + 1
                            EXIT DO
                        END IF 'x1
                    END IF '<>""
                LOOP
                macosx_libfind_failed:
                IF n = 0 THEN a$ = "Could not find sub/function '" + ResolveStaticFunction_Name(x) + "' in '" + ResolveStaticFunction_File(x) + "'": GOTO errmes
            END IF

        END IF
    NEXT

    IF INSTR(_OS$, "[MACOSX]") THEN

        ffh = FREEFILE
        OPEN tmpdir$ + "recompile_osx.command" FOR OUTPUT AS #ffh
        PRINT #ffh, "cd " + CHR_QUOTE + "$(dirname " + CHR_QUOTE + "$0" + CHR_QUOTE + ")" + CHR_QUOTE + CHR$(10);
        PRINT #ffh, "echo " + CHR_QUOTE + "Recompiling..." + CHR_QUOTE + CHR$(10);
        PRINT #ffh, "cd ../c" + CHR$(10);
        PRINT #ffh, makeline$ + CHR$(10);
        PRINT #ffh, "read -p " + CHR_QUOTE + "Press ENTER to exit..." + CHR_QUOTE + CHR$(10);
        CLOSE ffh
        SHELL _HIDE "chmod +x " + AddQuotes$(tmpdir$ + "recompile_osx.command")

        ffh = FREEFILE
        OPEN tmpdir$ + "debug_osx.command" FOR OUTPUT AS #ffh
        PRINT #ffh, "cd " + CHR_QUOTE + "$(dirname " + CHR_QUOTE + "$0" + CHR_QUOTE + ")" + CHR_QUOTE + CHR$(10);
        PRINT #ffh, "Pause()" + CHR$(10);
        PRINT #ffh, "{" + CHR$(10);
        PRINT #ffh, "OLDCONFIG=`stty -g`" + CHR$(10);
        PRINT #ffh, "stty -icanon -echo min 1 time 0" + CHR$(10);
        PRINT #ffh, "dd count=1 2>/dev/null" + CHR$(10);
        PRINT #ffh, "stty $OLDCONFIG" + CHR$(10);
        PRINT #ffh, "}" + CHR$(10);
        PRINT #ffh, "echo " + CHR_QUOTE + "C++ Debugging: " + file$ + extension$ + " using GDB" + CHR_QUOTE + CHR$(10);
        PRINT #ffh, "echo " + CHR_QUOTE + "Debugger commands:" + CHR_QUOTE + CHR$(10);
        PRINT #ffh, "echo " + CHR_QUOTE + "After the debugger launches type 'run' to start your program" + CHR_QUOTE + CHR$(10);
        PRINT #ffh, "echo " + CHR_QUOTE + "After your program crashes type 'list' to find where the problem is and fix/report it" + CHR_QUOTE + CHR$(10);
        PRINT #ffh, "echo " + CHR_QUOTE + "(the GDB debugger has many other useful commands, this advice is for beginners)" + CHR_QUOTE + CHR$(10);
        PRINT #ffh, "gdb " + CHR$(34) + path.exe$ + file$ + extension$ + CHR$(34) + CHR$(10);
        PRINT #ffh, "Pause" + CHR$(10);
        CLOSE ffh
        SHELL _HIDE "chmod +x " + AddQuotes$(tmpdir$ + "debug_osx.command")

    ELSE

        ffh = FREEFILE
        OPEN tmpdir$ + "recompile_lnx.sh" FOR OUTPUT AS #ffh
        PRINT #ffh, "#!/bin/sh" + CHR$(10);
        PRINT #ffh, "Pause()" + CHR$(10);
        PRINT #ffh, "{" + CHR$(10);
        PRINT #ffh, "OLDCONFIG=`stty -g`" + CHR$(10);
        PRINT #ffh, "stty -icanon -echo min 1 time 0" + CHR$(10);
        PRINT #ffh, "dd count=1 2>/dev/null" + CHR$(10);
        PRINT #ffh, "stty $OLDCONFIG" + CHR$(10);
        PRINT #ffh, "}" + CHR$(10);
        PRINT #ffh, "echo " + CHR_QUOTE + "Recompiling..." + CHR_QUOTE + CHR$(10);
        PRINT #ffh, "cd ../c" + CHR$(10);
        PRINT #ffh, makeline$ + CHR$(10);
        PRINT #ffh, "echo " + CHR_QUOTE + "Press ENTER to exit..." + CHR_QUOTE + CHR$(10);
        PRINT #ffh, "Pause" + CHR$(10);
        CLOSE ffh
        SHELL _HIDE "chmod +x " + AddQuotes$(tmpdir$ + "recompile_lnx.sh")

        ffh = FREEFILE
        OPEN tmpdir$ + "debug_lnx.sh" FOR OUTPUT AS #ffh
        PRINT #ffh, "#!/bin/sh" + CHR$(10);
        PRINT #ffh, "Pause()" + CHR$(10);
        PRINT #ffh, "{" + CHR$(10);
        PRINT #ffh, "OLDCONFIG=`stty -g`" + CHR$(10);
        PRINT #ffh, "stty -icanon -echo min 1 time 0" + CHR$(10);
        PRINT #ffh, "dd count=1 2>/dev/null" + CHR$(10);
        PRINT #ffh, "stty $OLDCONFIG" + CHR$(10);
        PRINT #ffh, "}" + CHR$(10);
        PRINT #ffh, "echo " + CHR_QUOTE + "C++ Debugging: " + file$ + extension$ + " using GDB" + CHR_QUOTE + CHR$(10);
        PRINT #ffh, "echo " + CHR_QUOTE + "Debugger commands:" + CHR_QUOTE + CHR$(10);
        PRINT #ffh, "echo " + CHR_QUOTE + "After the debugger launches type 'run' to start your program" + CHR_QUOTE + CHR$(10);
        PRINT #ffh, "echo " + CHR_QUOTE + "After your program crashes type 'list' to find where the problem is and fix/report it" + CHR_QUOTE + CHR$(10);
        PRINT #ffh, "echo " + CHR_QUOTE + "(the GDB debugger has many other useful commands, this advice is for beginners)" + CHR_QUOTE + CHR$(10);
        PRINT #ffh, "gdb " + CHR$(34) + path.exe$ + file$ + extension$ + CHR$(34) + CHR$(10);
        PRINT #ffh, "Pause" + CHR$(10);
        CLOSE ffh
        SHELL _HIDE "chmod +x " + AddQuotes$(tmpdir$ + "debug_lnx.sh")

    END IF

    IF NOT NoCCompileMode THEN
        SHELL _HIDE makeline$ + " 1>> " + compilelog$ + " 2>&1"
        IF idemode THEN
            'Restore fg/bg colors
            dummy = DarkenFGBG(0)
        END IF
    END IF

    IF INSTR(_OS$, "[MACOSX]") THEN
        ff = FREEFILE
        IF path.exe$ = "./" OR path.exe$ = "../../" OR path.exe$ = "..\..\" THEN path.exe$ = DefaultExeSaveFolder$
        OPEN path.exe$ + file$ + extension$ + "_start.command" FOR OUTPUT AS #ff
        PRINT #ff, "cd " + CHR$(34) + "$(dirname " + CHR$(34) + "$0" + CHR$(34) + ")" + CHR$(34);
        PRINT #ff, CHR$(10);
        PRINT #ff, "./" + CHR$(34) + file$ + extension$ + CHR$(34) + " &";
        PRINT #ff, CHR$(10);
        PRINT #ff, "osascript -e 'tell application " + CHR$(34) + "Terminal" + CHR$(34) + " to close (every window whose name contains " + CHR$(34) + file$ + extension$ + "_start.command" + CHR$(34) + ")' &";
        PRINT #ff, CHR$(10);
        PRINT #ff, "osascript -e 'if (count the windows of application " + CHR$(34) + "Terminal" + CHR$(34) + ") is 0 then tell application " + CHR$(34) + "Terminal" + CHR$(34) + " to quit' &";
        PRINT #ff, CHR$(10);
        PRINT #ff, "exit";
        PRINT #ff, CHR$(10);
        CLOSE #ff
        SHELL _HIDE "chmod +x " + AddQuotes$(path.exe$ + file$ + extension$ + "_start.command")
    END IF

END IF

IF NoCCompileMode THEN compfailed = 0: GOTO NoCCompile
IF path.exe$ = "../../" OR path.exe$ = "..\..\" THEN path.exe$ = DefaultExeSaveFolder$
IF _FILEEXISTS(path.exe$ + file$ + extension$) THEN
    compfailed = 0
    lastBinaryGenerated$ = path.exe$ + file$ + extension$
ELSE
    compfailed = 1 'detect compilation failure
END IF

IF compfailed THEN
    IF idemode THEN
        idemessage$ = "C++ Compilation failed " + CHR$(0) + "(Check " + _TRIM$(compilelog$) + ")"
        GOTO ideerror
    END IF
    IF compfailed THEN
        PRINT "ERROR: C++ compilation failed."
        PRINT "Check " + compilelog$ + " for details."
    END IF
ELSE
    IF idemode = 0 AND NOT QuietMode THEN
        location$ = lastBinaryGenerated$
        IF path.exe$ = "" THEN location$ = _CWD$ + location$
        PRINT "Output: "; RemoveDoubleSlashes$(location$)
    END IF
END IF

Skip_Build:



IF idemode THEN GOTO ideret6

NoCCompile:

IF (compfailed <> 0 OR warningsissued <> 0) AND NOT ConsoleMode THEN END 1
IF compfailed <> 0 THEN SYSTEM 1
SYSTEM 0

qberror_test:
E = 1
RESUME NEXT

qberror:
IF Debug THEN 'A more in-your-face error handler
    IF ConsoleMode THEN
        PRINT
    ELSE
        _AUTODISPLAY
        SCREEN _NEWIMAGE(80, 25, 0), , 0, 0
        COLOR 7, 0
    END IF
    _CONTROLCHR OFF
    PRINT "A QB error has occurred (and you have compiled in debugging support)."
    PRINT "Some key information (qb64pe.bas):"
    PRINT "Error"; ERR
    PRINT "Description: "; _ERRORMESSAGE$
    PRINT "Line"; _ERRORLINE
    IF _INCLERRORLINE THEN
        PRINT "Included line"; _INCLERRORLINE
        PRINT "Included file "; _INCLERRORFILE$
    END IF
    PRINT
    PRINT "Loaded source file details:"
    PRINT "ideerror ="; ideerror; "qberrorhappened ="; qberrorhappened; "qberrorhappenedvalue ="; qberrorhappenedvalue; "linenumber ="; linenumber
    PRINT "ca$ = {"; ca$; "}, idecommand$ = {"; idecommand$; "}"
    PRINT "linefragment = {"; linefragment; "}"
    END
END IF

IF ideerror THEN 'error happened inside the IDE
    fh = FREEFILE
    OPEN "internal\temp\ideerror.txt" FOR APPEND AS #fh
    PRINT #fh, DATE$; TIME$; "--------------------"
    PRINT #fh, ERR
    PRINT #fh, _ERRORMESSAGE$
    PRINT #fh, _ERRORLINE
    PRINT #fh, _INCLERRORLINE
    PRINT #fh, _INCLERRORFILE$
    CLOSE #fh
    sendc$ = CHR$(255) 'a runtime error has occurred
    RESUME sendcommand 'allow IDE to handle error recovery
END IF

qberrorhappenedvalue = qberrorhappened
qberrorhappened = 1

IF Debug THEN PRINT #9, "QB ERROR!"
IF Debug THEN PRINT #9, "ERR="; ERR
IF Debug THEN PRINT #9, "ERL="; ERL

IF idemode AND qberrorhappenedvalue >= 0 THEN
    'real qb error occurred
    ideerrorline = linenumber
    idemessage$ = "Compiler error (check for syntax errors) (" + _ERRORMESSAGE$ + ":"
    IF ERR THEN idemessage$ = idemessage$ + _TOSTR$(ERR) + "-"
    IF _ERRORLINE THEN idemessage$ = idemessage$ + _TOSTR$(_ERRORLINE)
    IF _INCLERRORLINE THEN idemessage$ = idemessage$ + "-" + _INCLERRORFILE$ + "-" + _TOSTR$(_INCLERRORLINE)
    idemessage$ = idemessage$ + ")"
    IF inclevel > 0 THEN idemessage$ = idemessage$ + incerror$
    RESUME ideerror
END IF

IF qberrorhappenedvalue >= 0 THEN
    a$ = "UNEXPECTED INTERNAL COMPILER ERROR!": GOTO errmes 'internal compiler error
END IF


qberrorcode = ERR
qberrorline = ERL
IF qberrorhappenedvalue = -1 THEN RESUME qberrorhappened1
IF qberrorhappenedvalue = -2 THEN RESUME qberrorhappened2
IF qberrorhappenedvalue = -3 THEN RESUME qberrorhappened3
END

errmes: 'set a$ to message
IF Error_Happened THEN a$ = Error_Message: Error_Happened = 0
layout$ = "": layoutok = 0 'invalidate layout

erldiff = 0
IF autoIncludingFile = 1 THEN 'IMPORTANT: don't omit "= 1" or change to "<> 0" !!
    'rewrite errors caused by vwatch/library auto-includes to be less confusing
    IF INSTR(a$, "END SUB/FUNCTION before") THEN a$ = "Expected END SUB/FUNCTION": incerror$ = ""
    IF a$ = "Name already in use (vwatch)" THEN a$ = "Syntax Error": incerror$ = "": erldiff = 1
    IF INSTR(a$, "SUB/FUNCTION not allowed") THEN erldiff = 1
END IF
IF inclevel > 0 AND incerror$ <> "" THEN a$ = a$ + CHR$(1) + incerror$

IF idemode THEN
    ideerrorline = linenumber + erldiff
    idemessage$ = a$
    GOTO ideerror 'infinitely preferable to RESUME
END IF
'non-ide mode output
PRINT
IF NOT MonochromeLoggingMode THEN
    IF INSTR(_OS$, "WIN") THEN
        COLOR 4
    ELSE
        COLOR 9
    END IF
END IF
PRINT a$
IF NOT MonochromeLoggingMode THEN COLOR 7
FOR i = 1 TO LEN(linefragment)
    IF MID$(linefragment, i, 1) = sp$ THEN MID$(linefragment, i, 1) = " "
NEXT
FOR i = 1 TO LEN(wholeline)
    IF MID$(wholeline, i, 1) = sp$ THEN MID$(wholeline, i, 1) = " "
NEXT
PRINT "Caused by (or after):" + linefragment
IF NOT MonochromeLoggingMode THEN COLOR 8
PRINT "LINE ";
IF NOT MonochromeLoggingMode THEN COLOR 15
PRINT _TOSTR$(linenumber) + ":";
IF NOT MonochromeLoggingMode THEN COLOR 7
PRINT wholeline

IF ConsoleMode THEN SYSTEM 1
END 1

FUNCTION ParseCMDLineArgs$ ()
    'Recall that COMMAND$ is a concatenation of argv[] elements, so we don't have
    'to worry about more than one space between things (unless they used quotes,
    'in which case they're simply asking for trouble).
    tmpKwCap = -5: tmpKwLow = -5 'mutual exclusive options, both invalidated here
    FOR i = 1 TO _COMMANDCOUNT
        token$ = COMMAND$(i)
        IF LCASE$(token$) = "/?" OR LCASE$(token$) = "/h" OR LCASE$(token$) = "--help" OR LCASE$(token$) = "/help" THEN token$ = "-?"
        SELECT CASE LCASE$(LEFT$(token$, 2))
            CASE "-?", "-h" 'Command-line help
                _DEST _CONSOLE
                IF NOT QB64VersionPrinted THEN QB64VersionPrinted = _TRUE: PRINT "QB64-PE Compiler V" + Version$
                PRINT
                PRINT "USAGE: qb64pe [options] <source file> [-o <output file>]"
                PRINT
                PRINT "Info Options (no files required):"
                PRINT "  -?, -h, --help       Show this help text"
                PRINT "  -v                   Show version information"
                PRINT
                PRINT "File specifications:"
                PRINT "  <source file>        Source file to load into IDE, to format or compile" '    '80 columns
                PRINT "  -o <output file>     Write result to <output file>"
                PRINT "                         - optionally override the default executable name"
                PRINT "                         - is mandatory for code formatting (-y option)"
                PRINT
                PRINT "IDE Options:"
                PRINT "  -l:<line number>     Load <source file> into the IDE and move cursor to"
                PRINT "                       the given <line number>, if possible"
                PRINT
                PRINT "Compiler Options (no IDE):"
                PRINT "  -c                   Compile <source file> (show progress in own window)"
                PRINT "  -x                   Like -c, but progress goes to console (no own window)"
                PRINT "  -y                   Output (re)formatted <source file> to -o <output file>"
                PRINT "  -z                   Generate C code from <source file> without compiling"
                PRINT "                       the executable (C code output goes to internal\temp)"
                PRINT "                         - may be used to quickly check for syntax errors"
                PRINT
                PRINT "Extended Compiler Options:"
                PRINT "  -p                   Purge all pre-compiled content first"
                PRINT "  -e                   Enforce variable declaration even if no OPTION _EXPLICIT"
                PRINT "                       was used in the <source file>"
                PRINT "                         - per compilation, doesn't change the <source file>"
                PRINT "  -s[:setting=value]   View and/or edit & save compiler settings permanently"
                PRINT
                PRINT "Temporary Compiler Options:"
                PRINT "  -f[:setting=value]   Compiler and/or formatting settings to use"
                PRINT "                         - per compilation, doesn't change global defaults"
                PRINT
                PRINT "Reporting Options:"
                PRINT "  -w                   Show warnings (such as unused variables etc.)"
                PRINT "  -q                   Quiet mode (no progress, but warnings/errors, if any)"
                PRINT "  -m                   Do not colorize compiler outputs (monochrome mode)"
                PRINT
                PRINT "     ----------------------------------------------------------------------"
                PRINT
                CMDLineSettingsHelp
                PRINT
                PRINT "     ----------------------------------------------------------------------"
                PRINT
                CMDLineTemporarySettingsHelp
                SYSTEM

            CASE "-v" ' Print version
                _DEST _CONSOLE
                IF NOT QB64VersionPrinted THEN QB64VersionPrinted = _TRUE: PRINT "QB64-PE Compiler V" + Version$
                SYSTEM

            CASE "-o" 'Specify an output file
                IF LEN(COMMAND$(i + 1)) > 0 THEN CMDLineOutFile$ = COMMAND$(i + 1): i = i + 1
                CMDLineSwitch = _TRUE

            CASE "-l" 'goto line (ide mode only); -l:<line number>
                IF MID$(token$, 3, 1) = ":" THEN IDEStartAtLine = VAL(MID$(token$, 4))
                CMDLineSwitch = _TRUE

            CASE "-c" 'Compile instead of edit
                NoIDEMode = _TRUE
                CMDLineSwitch = _TRUE

            CASE "-x" 'Use the console
                ConsoleMode = _TRUE
                NoIDEMode = _TRUE
                CMDLineSwitch = _TRUE

            CASE "-y" 'Format
                FormatMode = _TRUE
                ConsoleMode = _TRUE
                NoIDEMode = _TRUE
                QuietMode = _TRUE
                CMDLineSwitch = _TRUE

            CASE "-z" 'Not compiling C code
                NoCCompileMode = _TRUE
                ConsoleMode = _TRUE
                NoIDEMode = _TRUE
                CMDLineSwitch = _TRUE

            CASE "-p" 'Purge
                PurgeTemporaryBuildFiles (os$), (MacOSX)
                CMDLineSwitch = _TRUE

            CASE "-e" 'Option Explicit
                ForceOptExpl = _TRUE
                CMDLineSwitch = _TRUE

            CASE "-s" 'Settings
                SettingsMode = _TRUE
                setting$ = MID$(token$, 3)
                _DEST _CONSOLE
                IF NOT QB64VersionPrinted THEN QB64VersionPrinted = _TRUE: PRINT "QB64-PE Compiler V" + Version$: PRINT

                delim = INSTR(setting$, "="): eos = 0
                IF delim = 0 THEN delim = LEN(setting$) + 1: eos = -1 'end of string
                SELECT CASE LCASE$(LEFT$(setting$, delim - 1))
                    CASE ""
                        PRINT "DebugInfo     = "; BoolToTFString$(IncludeDebugInfo)
                        PRINT "ExeWithSource = "; BoolToTFString$(SaveExeWithSource)
                        PRINT "ExeDefaultDir = "; _IIF(LEN(DefaultExeSaveFolder$), DefaultExeSaveFolder$, "unset (= qb64pe folder)")
                        SYSTEM
                    CASE ":"
                        CMDLineSettingsError "Missing setting specification: " + token$, 0, 0
                    CASE ":debuginfo"
                        IF NOT eos THEN
                            IF NOT ParseBooleanSetting&(token$, IncludeDebugInfo) THEN CMDLineSettingsError token$, 1, 0
                            WriteConfigSetting compilerSettingsSection$, "IncludeDebugInfo", BoolToTFString$(IncludeDebugInfo)
                            PurgeTemporaryBuildFiles (os$), (MacOSX)
                        END IF
                        PRINT "DebugInfo = "; BoolToTFString$(IncludeDebugInfo)
                    CASE ":exewithsource"
                        IF NOT eos THEN
                            IF NOT ParseBooleanSetting&(token$, SaveExeWithSource) THEN CMDLineSettingsError token$, 1, 0
                            WriteConfigSetting generalSettingsSection$, "SaveExeWithSource", BoolToTFString$(SaveExeWithSource)
                        END IF
                        PRINT "ExeWithSource = "; BoolToTFString$(SaveExeWithSource)
                    CASE ":exedefaultdir"
                        IF NOT eos THEN
                            IF NOT ParseStringSetting&(token$, dexf$) THEN CMDLineSettingsError token$, 3, 0
                            IF LEN(dexf$) THEN
                                IF _DIREXISTS(_STARTDIR$ + dexf$) THEN dexf$ = _STARTDIR$ + dexf$
                                IF _DIREXISTS(dexf$) THEN
                                    dexf$ = _FULLPATH$(dexf$)
                                    WriteConfigSetting generalSettingsSection$, "DefaultExeSaveFolder", dexf$
                                    IF RIGHT$(dexf$, 1) <> pathsep$ THEN dexf$ = dexf$ + pathsep$
                                    DefaultExeSaveFolder$ = dexf$: dexf$ = "-1"
                                END IF
                            END IF
                            IF dexf$ <> "-1" THEN CMDLineSettingsError "Path not found: " + token$, 0, 0
                        END IF
                        PRINT "ExeDefaultDir = "; _IIF(LEN(DefaultExeSaveFolder$), DefaultExeSaveFolder$, "unset (= qb64pe folder)")
                    CASE ELSE
                        CMDLineSettingsError "Unsupported setting: " + token$, 0, 0
                END SELECT
                IF eos THEN SYSTEM 'was just a settings query
                _DEST 0

            CASE "-f" 'temporary setting
                SettingsMode = _TRUE
                setting$ = MID$(token$, 3)

                delim = INSTR(setting$, "=")
                IF delim = 0 THEN delim = LEN(setting$) + 1
                SELECT CASE LCASE$(LEFT$(setting$, delim - 1))
                    CASE ""
                        _DEST _CONSOLE
                        IF NOT QB64VersionPrinted THEN QB64VersionPrinted = _TRUE: PRINT "QB64-PE Compiler V" + Version$: PRINT
                        CMDLineTemporarySettingsHelp
                        SYSTEM
                    CASE ":"
                        CMDLineSettingsError "Missing setting specification: " + token$, 0, 1
                    CASE ":optimizecppprogram"
                        IF NOT ParseBooleanSetting&(token$, OptimizeCppProgram) THEN CMDLineSettingsError token$, 1, 1
                    CASE ":stripdebugsymbols"
                        IF NOT ParseBooleanSetting&(token$, StripDebugSymbols) THEN CMDLineSettingsError token$, 1, 1
                    CASE ":extracppflags"
                        IF NOT ParseStringSetting&(token$, ExtraCppFlags$) THEN CMDLineSettingsError token$, 3, 1
                    CASE ":extralinkerflags"
                        IF NOT ParseStringSetting&(token$, ExtraLinkerFlags$) THEN CMDLineSettingsError token$, 3, 1
                    CASE ":maxcompilerprocesses"
                        IF NOT ParseLongSetting&(token$, MaxParallelProcesses) THEN CMDLineSettingsError token$, 2, 1
                        IF MaxParallelProcesses < 1 OR MaxParallelProcesses > 128 THEN CMDLineSettingsError "MaxCompilerProcesses must be in range 1-128.", 0, 1
                    CASE ":generatelicensefile"
                        IF NOT ParseBooleanSetting&(token$, GenerateLicenseFile) THEN CMDLineSettingsError token$, 1, 1
                    CASE ":usesystemcompiler"
                        IF NOT ParseBooleanSetting&(token$, UseSystemMinGW) THEN CMDLineSettingsError token$, 1, 1
                    CASE ":autoindent"
                        IF NOT ParseBooleanSetting&(token$, IDEAutoIndent) THEN CMDLineSettingsError token$, 1, 1
                        DEFAutoIndent = IDEAutoIndent 'for restoring after '$FORMAT:OFF
                    CASE ":autoindentsize"
                        IF NOT ParseLongSetting&(token$, IDEAutoIndentSize) THEN CMDLineSettingsError token$, 2, 1
                        IF IDEAutoIndentSize < 1 OR IDEAutoIndentSize > 64 THEN CMDLineSettingsError "AutoIndentSize must be in range 1-64.", 0, 1
                    CASE ":indentsubs"
                        IF NOT ParseBooleanSetting&(token$, IDEIndentSubs) THEN CMDLineSettingsError token$, 1, 1
                    CASE ":autolayout"
                        IF NOT ParseBooleanSetting&(token$, IDEAutoLayout) THEN CMDLineSettingsError token$, 1, 1
                        DEFAutoLayout = IDEAutoLayout 'for restoring after '$FORMAT:OFF
                    CASE ":keywordcapitals"
                        IF NOT ParseBooleanSetting&(token$, tmpKwCap) THEN CMDLineSettingsError token$, 1, 1
                    CASE ":keywordlowercase"
                        IF NOT ParseBooleanSetting&(token$, tmpKwLow) THEN CMDLineSettingsError token$, 1, 1
                    CASE ELSE
                        CMDLineSettingsError "Unsupported setting: " + token$, 0, 1
                END SELECT

            CASE "-w" 'Show warnings
                ShowWarnings = _TRUE
                CMDLineSwitch = _TRUE

            CASE "-q" 'Quiet mode
                QuietMode = _TRUE
                CMDLineSwitch = _TRUE

            CASE "-m" 'Monochrome mode
                MonochromeLoggingMode = _TRUE
                CMDLineSwitch = _TRUE

            CASE "-u" 'Invoke "Update all pages" to populate internal/help files (hidden CI build option)
                Help_Recaching = 2: Help_IgnoreCache = 0
                IF ideupdatehelpbox THEN
                    _DEST _CONSOLE
                    PRINT "Help update incomplete, missing pages will be fetched on demand when a user requests it."
                    SYSTEM 1
                END IF
                SYSTEM

            CASE ELSE 'Something we don't recognise, assume it's a filename
                IF PassedFileName$ = "" THEN PassedFileName$ = token$
        END SELECT
    NEXT i
    'check if mutual exclusive options were given and accordingly adjust setting
    IF tmpKwCap > -5 OR tmpKwLow > -5 THEN 'any of it given? - No: stay with default
        IF tmpKwCap = tmpKwLow THEN 'both set or unset = CaMeL case
            IDEAutoLayoutKwStyle = _EQUAL
        ELSEIF tmpKwCap = _TRUE THEN '= UPPER case
            IDEAutoLayoutKwStyle = _GREATER
        ELSEIF tmpKwLow = _TRUE THEN '= lower case
            IDEAutoLayoutKwStyle = _LESS
        END IF
    END IF
    'don't leak force option into the IDE or the code formatter
    IF NOT NoIDEMode THEN ForceOptExpl = _FALSE

    IF FormatMode AND LEN(CMDLineOutFile$) = 0 THEN
        _DEST _CONSOLE
        PRINT "Formatting requires specifying output file with -o option"
        SYSTEM 1
    END IF

    IF LEN(PassedFileName$) THEN
        ParseCMDLineArgs$ = PassedFileName$
    ELSE
        IF NOT CMDLineSwitch AND SettingsMode THEN SYSTEM
    END IF
END FUNCTION

SUB CMDLineSettingsError (errstr$, typ%, tmp%)
    'errstr$ = the token$ only for types 1-3, else any custom message
    'typ% = 1 (invalid bool) / = 2 (missing integer) / = 3 (missing string) / else (custom message)
    'tmp% <> 0 (-f temp setting) / = 0 (-s permanent setting)
    _DEST _CONSOLE
    IF NOT QB64VersionPrinted THEN QB64VersionPrinted = _TRUE: PRINT "QB64-PE Compiler V" + Version$: PRINT

    SELECT CASE typ%
        CASE 1
            PRINT "Invalid boolean value for "; _IIF(tmp%, "temporary (-f)", "(-s)"); " setting: "; errstr$
            PRINT "   enable: "; _IIF(tmp%, "-f", "-s"); ":setting=[true|on|yes|1|-1]"
            PRINT "  disable: "; _IIF(tmp%, "-f", "-s"); ":setting=[false|off|no|0]"
        CASE 2, 3
            PRINT "Missing value for "; _IIF(tmp%, "temporary (-f)", "(-s)"); " setting: "; errstr$
            PRINT "  expected: "; _IIF(tmp%, "-f", "-s"); ":setting=["; _IIF(typ% = 2, "number", "string"); "]"
        CASE ELSE
            PRINT errstr$
    END SELECT
    PRINT

    IF tmp% THEN CMDLineTemporarySettingsHelp ELSE CMDLineSettingsHelp
    SYSTEM 1
END SUB

SUB CMDLineSettingsHelp
    PRINT "Supported (-s) Compiler settings:"
    PRINT "  -s                              Show the current state of all settings"
    PRINT "  -s:DebugInfo=[true|false]       Embed C++ debug info into executable"
    PRINT "  -s:ExeWithSource=[true|false]   Save executable in the source folder"
    PRINT "  -s:ExeDefaultDir=[string]       Save executables here per default,"
    PRINT "                                  if not saving with source"
    PRINT "      You may specify a setting without equal sign and value to"
    PRINT "      show the current state of that specific setting only."
END SUB

SUB CMDLineTemporarySettingsHelp
    PRINT "Note:" '                                                                        '80 columns
    PRINT "  Defaults for the following settings can be set via the IDE Options menu,"
    PRINT "  any values given here are just temporary overrides per compilation."
    PRINT
    PRINT "Supported (-f) Compiler settings:"
    PRINT "  -f                                    Show this list of supported settings"
    PRINT "  -f:OptimizeCppProgram=[true|false]    Compile with C++ Optimization flag"
    PRINT "  -f:StripDebugSymbols=[true|false]     Strip C++ Symbols from executable"
    PRINT "  -f:ExtraCppFlags=[string]             Extra flags for the C++ Compiler"
    PRINT "  -f:ExtraLinkerFlags=[string]          Extra flags for the Linker"
    PRINT "  -f:MaxCompilerProcesses=[integer]     Max C++ Compiler processes to use"
    PRINT "  -f:GenerateLicenseFile=[true|false]   Produce a license.txt file for program"
    PRINT "  -f:UseSystemCompiler=[true|false]     Use the system C++ compiler instead of"
    PRINT "                                        the bundled one (Windows only)"
    PRINT
    PRINT "Supported (-f) Layout settings:"
    PRINT "  -f:AutoIndent=[true|false]            Auto Indent lines"
    PRINT "      The next two also require the above to be enabled or they will have"
    PRINT "      no effect, unless AutoIndent is enabled per default in the IDE."
    PRINT "  -f:AutoIndentSize=[integer]           Indent Spacing per indent level"
    PRINT "  -f:IndentSubs=[true|false]            Indent SUBs and FUNCTIONs"
    PRINT "  -f:AutoLayout=[true|false]            Auto Single-spacing of code elements"
    PRINT "      The next two work together, if both are given with the same state"
    PRINT "      it's CaMeL case, otherwise the enabled one determines the case,"
    PRINT "      hence no need to specify both if you just want UPPER or lower case."
    PRINT "      If none is given the default as set in the IDE is used."
    PRINT "  -f:KeywordCapitals=[true|false]       Make keywords to ALL CAPITALS"
    PRINT "  -f:KeywordLowercase=[true|false]      Make keywords to ALL lower case"
END SUB

FUNCTION ParseBooleanSetting& (token$, setting AS LONG)
    DIM equals AS LONG
    DIM value AS STRING

    equals = INSTR(token$, "=")
    IF equals = 0 THEN ParseBooleanSetting& = 0: EXIT FUNCTION

    value = LCASE$(MID$(token$, equals + 1))

    SELECT CASE value
        CASE "true", "on", "yes", "1", "-1"
            setting = _TRUE
            ParseBooleanSetting& = -1

        CASE "false", "off", "no", "0"
            setting = _FALSE
            ParseBooleanSetting& = -1

        CASE ELSE
            ParseBooleanSetting& = 0
    END SELECT
END FUNCTION

FUNCTION ParseLongSetting& (token$, setting AS LONG)
    DIM equals AS LONG

    equals = INSTR(token$, "=")
    IF equals = 0 THEN ParseLongSetting& = 0: EXIT FUNCTION

    setting = VAL(MID$(token$, equals + 1))

    ParseLongSetting& = -1
END FUNCTION

FUNCTION ParseStringSetting& (token$, setting AS STRING)
    DIM equals AS LONG

    equals = INSTR(token$, "=")
    IF equals = 0 THEN ParseStringSetting& = 0: EXIT FUNCTION

    setting = MID$(token$, equals + 1)

    ParseStringSetting& = -1
END FUNCTION

FUNCTION Type2MemTypeValue (t1)
    t = 0
    IF t1 AND ISARRAY THEN t = t + 65536
    IF t1 AND ISUDT THEN
        IF (t1 AND UDTMASK) = 1 THEN
            t = t + 4096 '_MEM type
        ELSE
            t = t + 32768
        END IF
    ELSE
        IF t1 AND ISSTRING THEN
            t = t + 512 'string
        ELSE
            IF t1 AND ISFLOAT THEN
                t = t + 256 'float
            ELSE
                t = t + 128 'integer
                IF t1 AND ISUNSIGNED THEN t = t + 1024
                IF t1 AND ISOFFSET THEN t = t + 8192 'offset type
            END IF
            t1s = (t1 AND UDTMASK) \ 8
            IF t1s = 1 THEN t = t + t1s
            IF t1s = 2 THEN t = t + t1s
            IF t1s = 4 THEN t = t + t1s
            IF t1s = 8 THEN t = t + t1s
            IF t1s = 16 THEN t = t + t1s
            IF t1s = 32 THEN t = t + t1s
            IF t1s = 64 THEN t = t + t1s
        END IF
    END IF
    Type2MemTypeValue = t
END FUNCTION


'Return the declaration-driven physical-layout mode for a TYPE graph.
'Zero means inline-only; one means canonical descriptor-aware layout.
FUNCTION GetUDTCanonMode& (udt AS LONG)
    ' Invalid/no TYPE index maps to inline-only mode 0, matching BASIC's default numeric return.
    IF udt <= 0 OR udt > UBOUND(udtxcanonmode) THEN EXIT FUNCTION
    GetUDTCanonMode& = udtxcanonmode(udt)
END FUNCTION



'udt is non-zero if this is an array of udt's, to allow examining each udt element
FUNCTION allocarray (n2$, elements$, elementsize, udt)
    dimsharedlast = dimshared: dimshared = 0
    dynarrmode = udt_alloc_dynmode

    IF autoarray = 1 THEN autoarray = 0: autoary = 1 'clear global value & set local value

    f12Buf% = CreateBuf% 'temporary buffer for code accumulation

    'changelog:
    'added 4 to [2] to indicate cmem array where appropriate

    e$ = elements$: n$ = n2$
    IF elementsize = -2147483647 THEN stringarray = 1: elementsize = 8

    IF ASC(e$) = 63 THEN '?
        l$ = "(" + sp2 + ")"
        undefined = -1
        nume = 1
        IF LEN(e$) = 1 THEN GOTO undefinedarray
        undefined = 1
        nume = VAL(RIGHT$(e$, LEN(e$) - 1))
        GOTO undefinedarray
    END IF


    'work out how many elements there are (critical to later calculations)
    nume = 1
    n = numelements(e$)
    FOR i = 1 TO n
        e2$ = getelement(e$, i)
        IF e2$ = "(" THEN b = b + 1
        IF b = 0 AND e2$ = "," THEN nume = nume + 1
        IF e2$ = ")" THEN b = b - 1
    NEXT
    IF Debug THEN PRINT #9, "numelements count:"; nume

    descstatic = 0
    IF arraydesc THEN
        IF id.arrayelements <> nume THEN

            IF id.arrayelements = -1 THEN 'unknown
                IF arrayelementslist(currentid) <> 0 AND nume <> arrayelementslist(currentid) THEN Give_Error "Cannot change the number of elements an array has!": EXIT FUNCTION
                IF nume = 1 THEN id.arrayelements = 1: ids(currentid).arrayelements = 1 'lucky guess!
                arrayelementslist(currentid) = nume
            ELSE
                Give_Error "Cannot change the number of elements an array has!": EXIT FUNCTION
            END IF

        END IF
        IF id.staticarray THEN descstatic = 1
    END IF

    l$ = "(" + sp2

    cr$ = CHR$(13) + CHR$(10)
    sd$ = ""
    constdimensions = 1
    ei = 4 + nume * 4 - 4
    cure = 1
    e3$ = "": e3base$ = ""
    FOR i = 1 TO n
        e2$ = getelement(e$, i)
        IF e2$ = "(" THEN b = b + 1
        IF (e2$ = "," AND b = 0) OR i = n THEN
            IF i = n THEN e3$ = e3$ + sp + e2$
            e3$ = RIGHT$(e3$, LEN(e3$) - 1)
            IF e3base$ <> "" THEN e3base$ = RIGHT$(e3base$, LEN(e3base$) - 1)
            'PRINT e3base$ + "[TO]" + e3$
            'set the base

            basegiven = 1
            IF e3base$ = "" THEN
                ' Keep the classic zero-element bootstrap idiom valid:
                ' DIM A(0) / REDIM A(0) must create a valid 0 TO 0 array,
                ' even if OPTION BASE 1 is currently active.
                IF LTRIM$(RTRIM$(e3$)) = "0" THEN
                    e3base$ = "0"
                ELSE
                    e3base$ = _TOSTR$(optionbase + 0)
                END IF
                basegiven = 0
            END IF
            constequation = 1

            e3base$ = fixoperationorder$(e3base$)
            IF Error_Happened THEN EXIT FUNCTION
            IF basegiven THEN l$ = l$ + tlayout$ + sp + SCase$("To") + sp
            e3base$ = evaluatetotyp$(e3base$, 64&)
            IF Error_Happened THEN EXIT FUNCTION

            IF constequation = 0 THEN constdimensions = 0
            lower_bound_is_const = constequation
            sd$ = sd$ + n$ + "[" + _TOSTR$(ei) + "]=" + e3base$ + ";" + cr$
            'set the number of indexes
            constequation = 1

            e3$ = fixoperationorder$(e3$)
            IF Error_Happened THEN EXIT FUNCTION
            l$ = l$ + tlayout$ + sp2
            IF i = n THEN l$ = l$ + ")" ELSE l$ = l$ + "," + sp
            e3$ = evaluatetotyp$(e3$, 64&)
            IF Error_Happened THEN EXIT FUNCTION

            IF constequation = 0 THEN constdimensions = 0
            upper_bound_is_const = constequation
            ' Catch constant reversed bounds here and guard runtime bounds below.
            ' Explicit TO ranges reject reversed bounds.
            ' Single-bound declarations reject only negative constants.
            IF upper_bound_is_const THEN
                IF basegiven THEN
                    IF lower_bound_is_const THEN
                        IF VAL(e3$) < VAL(e3base$) THEN Give_Error "Invalid array bounds": EXIT FUNCTION
                    END IF
                ELSE
                    IF VAL(e3$) < 0 THEN Give_Error "Invalid array bounds": EXIT FUNCTION
                END IF
            END IF

            ei = ei + 1
            sd$ = sd$ + n$ + "[" + _TOSTR$(ei) + "]=(" + e3$ + ")-" + n$ + "[" + _TOSTR$(ei - 1) + "]+1;" + cr$
            sd$ = sd$ + "if (" + n$ + "[" + _TOSTR$(ei) + "]<=0) error(5);" + cr$
            ei = ei + 1
            'calc muliplier
            IF cure = 1 THEN
                'set only for the purpose of the calculating correct multipliers
                sd$ = sd$ + n$ + "[" + _TOSTR$(ei) + "]=1;" + cr$
            ELSE
                sd$ = sd$ + n$ + "[" + _TOSTR$(ei) + "]=" + n$ + "[" + _TOSTR$(ei + 4) + "]*" + n$ + "[" + _TOSTR$(ei + 3) + "];" + cr$
            END IF
            ei = ei + 1
            ei = ei + 1 'skip reserved
            ei = ei - 8
            cure = cure + 1
            e3$ = "": e3base$ = ""
            GOTO aanexte
        END IF
        IF e2$ = ")" THEN b = b - 1
        IF UCASE$(e2$) = "TO" AND b = 0 THEN
            e3base$ = e3$
            e3$ = ""
        ELSE
            e3$ = e3$ + sp + e2$
        END IF
        aanexte:
    NEXT
    sd$ = LEFT$(sd$, LEN(sd$) - 2)

    undefinedarray:

    'calc cmem
    cmem = 0
    IF arraydesc = 0 THEN
        IF cmemlist(idn + 1) THEN cmem = 1
    ELSE
        IF cmemlist(arraydesc) THEN cmem = 1
    END IF

    staticarray = constdimensions
    IF subfuncn <> 0 AND dimstatic = 0 THEN staticarray = 0 'arrays in SUBS/FUNCTIONS are DYNAMIC
    IF dimstatic = 3 THEN staticarray = 0 'STATIC arrayname() listed arrays keep their values but are dynamic in memory
    IF DynamicMode THEN staticarray = 0
    IF redimoption THEN staticarray = 0
    IF dimoption = 3 THEN staticarray = 0 'STATIC a(100) arrays are still dynamic

    IF arraydesc THEN
        IF staticarray = 1 THEN
            IF descstatic THEN Give_Error "Cannot redefine a static array!": EXIT FUNCTION
            staticarray = 0
        END IF
    END IF






    bytesperelement$ = _TOSTR$(elementsize)
    IF elementsize < 0 THEN
        elementsize = -elementsize
        bytesperelement$ = _TOSTR$(elementsize) + "/8+1"
    END IF


    'Begin creation of array descriptor (if array has not been defined yet)
    IF arraydesc = 0 THEN
        WriteBufLine defdatahandle, "ptrszint *" + n$ + "=NULL;"
        WriteBufLine DataTxtBuf, "if (!" + n$ + "){"
        WriteBufLine DataTxtBuf, n$ + "=(ptrszint*)mem_static_malloc(" + _TOSTR$(4 * nume + 4 + 1) + "*ptrsz);" '+1 is for the lock
        'create _MEM lock
        WriteBufLine DataTxtBuf, "new_mem_lock();"
        WriteBufLine DataTxtBuf, "mem_lock_tmp->type=4;"
        WriteBufLine DataTxtBuf, "((ptrszint*)" + n$ + ")[" + _TOSTR$(4 * nume + 4 + 1 - 1) + "]=(ptrszint)mem_lock_tmp;"
    END IF

    'generate sizestr$ & elesizestr$ (both are used in various places in following code)
    sizestr$ = ""
    FOR i = 1 TO nume
        IF i <> 1 THEN sizestr$ = sizestr$ + "*"
        sizestr$ = sizestr$ + n$ + "[" + _TOSTR$(i * 4 - 4 + 5) + "]"
    NEXT
    elesizestr$ = sizestr$ 'elements in entire array
    sizestr$ = sizestr$ + "*" + bytesperelement$ 'bytes in entire array

    'Build alternative descriptor/size expressions for dynamic arrays.
    'These let the generated C code validate and allocate first, and only then
    'commit the descriptor back into the real array descriptor.
    newsd$ = StrReplace$(sd$, n$ + "[", "alloc_new_desc[")
    newelesizestr$ = StrReplace$(elesizestr$, n$ + "[", "alloc_new_desc[")
    newsizestr$ = StrReplace$(sizestr$, n$ + "[", "alloc_new_desc[")
    commitdesc$ = ""
    FOR i = 4 TO 4 + nume * 4 - 1
        commitdesc$ = commitdesc$ + n$ + "[" + _TOSTR$(i) + "]=alloc_new_desc[" + _TOSTR$(i) + "];" + cr$
    NEXT
    IF LEN(commitdesc$) THEN commitdesc$ = LEFT$(commitdesc$, LEN(commitdesc$) - 2)



    '------------------STATIC ARRAY CREATION--------------------------------
    IF staticarray THEN
        'STATIC memory
        WriteBufLine DataTxtBuf, sd$ 'setup new array dimension ranges
        'Example of sd$ for DIM a(10):
        '__ARRAY_SINGLE_A[4]= 0 ;
        '__ARRAY_SINGLE_A[5]=( 10 )-__ARRAY_SINGLE_A[4]+1;
        '__ARRAY_SINGLE_A[6]=1;
        IF cmem AND stringarray = 0 THEN
            'Note: A string array's pointers are always stored in 64bit memory
            '(static)CONVENTIONAL memory
            WriteBufLine DataTxtBuf, n$ + "[0]=(ptrszint)cmem_static_pointer;"
            'alloc mem & check if static memory boundary has overstepped dynamic memory boundary
            WriteBufLine DataTxtBuf, "if ((cmem_static_pointer+=((" + sizestr$ + ")+15)&-16)>cmem_dynamic_base) error(257);"
            '64K check
            WriteBufLine DataTxtBuf, "if ((" + sizestr$ + ")>65536) error(257);"
            'clear array
            WriteBufLine DataTxtBuf, "memset((void*)(" + n$ + "[0]),0," + sizestr$ + ");"
            'set flags
            WriteBufLine DataTxtBuf, n$ + "[2]=1+2+4;" 'init+static+cmem
        ELSE
            '64BIT MEMORY
            WriteBufLine DataTxtBuf, n$ + "[0]=(ptrszint)mem_static_malloc(" + sizestr$ + ");"
            IF stringarray THEN
                'Init string pointers in the array
                WriteBufLine DataTxtBuf, "tmp_long=" + elesizestr$ + ";"
                WriteBufLine DataTxtBuf, "while(tmp_long--){"
                IF cmem THEN
                    WriteBufLine DataTxtBuf, "((uint64*)(" + n$ + "[0]))[tmp_long]=(uint64)qbs_new_cmem(0,0);"
                ELSE
                    WriteBufLine DataTxtBuf, "((uint64*)(" + n$ + "[0]))[tmp_long]=(uint64)qbs_new(0,0);"
                END IF
                WriteBufLine DataTxtBuf, "}"
            ELSE
                'clear array
                WriteBufLine DataTxtBuf, "memset((void*)(" + n$ + "[0]),0," + sizestr$ + ");"
            END IF
            WriteBufLine DataTxtBuf, n$ + "[2]=1+2;" 'init+static
        END IF

        IF udt > 0 AND dynarrmode <> 0 THEN
            IF UDTDynHasMemberArrays%(udt, dynarrmode) THEN
                ' A DIM/static-storage parent array still needs descriptor initialization when
                ' its TYPE graph contains explicit _Dynamic members. Parent storage remains fixed,
                ' while each element owns live member-array descriptors that require lifecycle handling.
                WriteBufLine DataTxtBuf, n$ + "[2]|=8;" 'dynamic UDT descriptor-layout flag
                WriteBufLine DataTxtBuf, "tmp_long=" + elesizestr$ + ";"
                WriteBufLine DataTxtBuf, "while(tmp_long--){"
                acc$ = ""
                AppendDynUDTDescInit n$, udt, 0, bytesperelement$, acc$, dynarrmode
                IF Error_Happened THEN EXIT FUNCTION
                WriteBufLine DataTxtBuf, acc$
                WriteBufLine DataTxtBuf, "}"
            END IF
        END IF

        IF udt > 0 AND udtxvariable(udt) AND NOT (dynarrmode <> 0 AND UDTDynHasMemberArrays%(udt, dynarrmode)) THEN
            WriteBufLine DataTxtBuf, "tmp_long=" + elesizestr$ + ";"
            WriteBufLine DataTxtBuf, "while(tmp_long--){"
            initialise_array_udt_varstrings n$, udt, 0, bytesperelement$, acc$
            WriteBufLine DataTxtBuf, acc$
            WriteBufLine DataTxtBuf, "}"
        END IF

        'Close static array desc
        WriteBufLine DataTxtBuf, "}"
        allocarray = nume + 65536
    END IF
    '------------------END OF STATIC ARRAY CREATION-------------------------

    '------------------DYNAMIC ARRAY CREATION-------------------------------
    IF staticarray = 0 THEN

        IF undefined = 0 THEN



            'Generate error if array is static
            WriteBufLine f12Buf%, "if (" + n$ + "[2]&2){" 'static array
            WriteBufLine f12Buf%, "error(10);" 'cannot redefine a static array!
            WriteBufLine f12Buf%, "}else{"
            'Note: Array is either undefined or dynamically defined at this point


            'REDIM (not DIM) must be used to redefine an array
            WriteBufLine f12Buf%, "static int64 alloc_new_desc[" + _TOSTR$(4 * nume + 4) + "];"
            WriteBufLine f12Buf%, "static uint64 alloc_req_elems;"
            WriteBufLine f12Buf%, "static uint64 alloc_req_bytes;"
            WriteBufLine f12Buf%, "static uint64 alloc_dim_value;"
            WriteBufLine f12Buf%, "static uint64 alloc_bytes_per_element;"
            IF redimoption = 0 THEN
                WriteBufLine f12Buf%, "if (" + n$ + "[2]&1){" 'array is defined
                WriteBufLine f12Buf%, "if (!error_occurred) error(10);" 'cannot redefine an array without using REDIM!
                WriteBufLine f12Buf%, "}else{"
            ELSE
                '--------CAPTURE EXISTING ARRAY IF NECESSARY--------
                'Do not destroy the old allocation until the new one has succeeded.

                'refresh lock ID (_MEM)
                WriteBufLine f12Buf%, "((mem_lock*)((ptrszint*)" + n$ + ")[" + _TOSTR$(4 * nume + 4 + 1 - 1) + "])->id=(++mem_lock_id);"
                WriteBufLine f12Buf%, "static ptrszint preserve_old_ptr;"
                WriteBufLine f12Buf%, "static ptrszint preserve_old_flags;"
                WriteBufLine f12Buf%, "static uint64 preserve_old_total;"
                WriteBufLine f12Buf%, "static uint64 preserve_new_total;"
                WriteBufLine f12Buf%, "static uint64 preserve_copy_count;"
                WriteBufLine f12Buf%, "static ptrszint preserve_new_ptr;"
                IF redimoption = 3 THEN
                    WriteBufLine f12Buf%, "static int32 preserve_any;"
                    WriteBufLine f12Buf%, "static int64 preserve_old_desc[" + _TOSTR$(4 * nume + 4) + "];"
                    WriteBufLine f12Buf%, "static int64 preserve_lo[" + _TOSTR$(nume) + "];"
                    WriteBufLine f12Buf%, "static int64 preserve_hi[" + _TOSTR$(nume) + "];"
                    WriteBufLine f12Buf%, "static int64 preserve_idx[" + _TOSTR$(nume) + "];"
                    WriteBufLine f12Buf%, "static int64 preserve_old_off;"
                    WriteBufLine f12Buf%, "static int64 preserve_new_off;"
                    WriteBufLine f12Buf%, "static ptrszint preserve_dim;"
                END IF

                WriteBufLine f12Buf%, "if (" + n$ + "[2]&1){" 'array is defined
                WriteBufLine f12Buf%, "preserve_old_ptr=" + n$ + "[0];"
                WriteBufLine f12Buf%, "preserve_old_flags=" + n$ + "[2];"
                WriteBufLine f12Buf%, "preserve_old_total=" + elesizestr$ + ";"
                IF redimoption = 3 THEN
                    FOR i = 4 TO 4 + nume * 4 - 1
                        WriteBufLine f12Buf%, "preserve_old_desc[" + _TOSTR$(i) + "]=" + n$ + "[" + _TOSTR$(i) + "];"
                    NEXT
                END IF
                WriteBufLine f12Buf%, "}else{"
                WriteBufLine f12Buf%, "preserve_old_total=0; preserve_old_ptr=0; preserve_old_flags=0; preserve_new_total=0; preserve_copy_count=0;"
                IF redimoption = 3 THEN WriteBufLine f12Buf%, "preserve_any=0;"
                WriteBufLine f12Buf%, "}"
                '--------EXISTING ARRAY CAPTURED AS NECESSARY--------
            END IF 'redim specified


            '--------CREATE ARRAY & CLEAN-UP CODE--------
            'Build the new descriptor in temporary storage first.
            WriteBufLine f12Buf%, newsd$
            WriteBufLine f12Buf%, "alloc_req_elems=1;"
            WriteBufLine f12Buf%, "alloc_bytes_per_element=(uint64)(" + bytesperelement$ + ");"
            WriteBufLine f12Buf%, "if (!alloc_bytes_per_element) error(257);"
            FOR i = 1 TO nume
                argi = i * 4 - 4 + 4
                WriteBufLine f12Buf%, "if (((int64)((ptrszint)alloc_new_desc[" + _TOSTR$(argi) + "]))!=alloc_new_desc[" + _TOSTR$(argi) + "]) error(257);"
                WriteBufLine f12Buf%, "if (alloc_new_desc[" + _TOSTR$(argi + 1) + "]<0) error(257);"
                WriteBufLine f12Buf%, "if (((int64)((ptrszint)alloc_new_desc[" + _TOSTR$(argi + 1) + "]))!=alloc_new_desc[" + _TOSTR$(argi + 1) + "]) error(257);"
                WriteBufLine f12Buf%, "if (alloc_new_desc[" + _TOSTR$(argi + 2) + "]<0) error(257);"
                WriteBufLine f12Buf%, "if (((int64)((ptrszint)alloc_new_desc[" + _TOSTR$(argi + 2) + "]))!=alloc_new_desc[" + _TOSTR$(argi + 2) + "]) error(257);"
                WriteBufLine f12Buf%, "alloc_dim_value=(uint64)alloc_new_desc[" + _TOSTR$(argi + 1) + "];"
                WriteBufLine f12Buf%, "if (alloc_dim_value){"
                WriteBufLine f12Buf%, "if (alloc_req_elems>(18446744073709551615ull/alloc_dim_value)) error(257);"
                WriteBufLine f12Buf%, "alloc_req_elems*=alloc_dim_value;"
                WriteBufLine f12Buf%, "}"
            NEXT
            WriteBufLine f12Buf%, "if (alloc_req_elems>(18446744073709551615ull/alloc_bytes_per_element)) error(257);"
            WriteBufLine f12Buf%, "alloc_req_bytes=alloc_req_elems*alloc_bytes_per_element;"
            WriteBufLine f12Buf%, "if (((uint64)((ptrszint)alloc_req_elems))!=alloc_req_elems) error(257);"
            WriteBufLine f12Buf%, "if (((uint64)((size_t)alloc_req_bytes))!=alloc_req_bytes) error(257);"

            IF redimoption THEN
                WriteBufLine f12Buf%, "preserve_new_total=alloc_req_elems;"
                WriteBufLine f12Buf%, "preserve_copy_count=preserve_old_total;"
                WriteBufLine f12Buf%, "if (preserve_new_total<preserve_copy_count) preserve_copy_count=preserve_new_total;"
            END IF

            IF redimoption = 3 THEN 'for _Retain, preserve overlap region by coordinates
                WriteBufLine f12Buf%, "preserve_any=(preserve_old_total!=0);"
                FOR i = 1 TO nume
                    argi = (nume - i) * 4 + 4
                    WriteBufLine f12Buf%, "preserve_lo[" + _TOSTR$(i - 1) + "]=alloc_new_desc[" + _TOSTR$(argi) + "];"
                    WriteBufLine f12Buf%, "if (preserve_old_desc[" + _TOSTR$(argi) + "]>preserve_lo[" + _TOSTR$(i - 1) + "]) preserve_lo[" + _TOSTR$(i - 1) + "]=preserve_old_desc[" + _TOSTR$(argi) + "];"
                    WriteBufLine f12Buf%, "preserve_hi[" + _TOSTR$(i - 1) + "]=alloc_new_desc[" + _TOSTR$(argi) + "]+(alloc_new_desc[" + _TOSTR$(argi + 1) + "]-1);"
                    WriteBufLine f12Buf%, "if ((preserve_old_desc[" + _TOSTR$(argi) + "]+(preserve_old_desc[" + _TOSTR$(argi + 1) + "]-1))<preserve_hi[" + _TOSTR$(i - 1) + "]) preserve_hi[" + _TOSTR$(i - 1) + "]=preserve_old_desc[" + _TOSTR$(argi) + "]+(preserve_old_desc[" + _TOSTR$(argi + 1) + "]-1);"
                    WriteBufLine f12Buf%, "if (preserve_hi[" + _TOSTR$(i - 1) + "]<preserve_lo[" + _TOSTR$(i - 1) + "]) preserve_any=0;"
                NEXT
            END IF

            IF stringarray OR ((udt > 0) AND udtxvariable(udt) AND NOT (dynarrmode <> 0 AND UDTDynHasMemberArrays%(udt, dynarrmode))) THEN

                'Note: String and variable-length udt arrays are always created in 64bit memory

                IF redimoption THEN
                    WriteBufLine f12Buf%, "if (preserve_old_total){"
                    WriteBufLine f12Buf%, "preserve_new_ptr=(ptrszint)malloc((size_t)alloc_req_bytes);"
                    WriteBufLine f12Buf%, "if (!preserve_new_ptr) error(257);" 'not enough memory
                    WriteBufLine f12Buf%, n$ + "[0]=preserve_new_ptr;"
                    WriteBufLine f12Buf%, n$ + "[2]|=1;" 'ADD initialized flag
                    WriteBufLine f12Buf%, "tmp_long=(ptrszint)alloc_req_elems;"

                    'init individual strings / var-len UDT members in the NEW array
                    IF stringarray THEN
                        WriteBufLine f12Buf%, "if (" + n$ + "[2]&4){" 'array/string content in cmem
                        WriteBufLine f12Buf%, "while(tmp_long--) ((uint64*)(" + n$ + "[0]))[tmp_long]=(uint64)qbs_new_cmem(0,0);"
                        WriteBufLine f12Buf%, "}else{" 'not in cmem
                        WriteBufLine f12Buf%, "while(tmp_long--) ((uint64*)(" + n$ + "[0]))[tmp_long]=(uint64)qbs_new(0,0);"
                        WriteBufLine f12Buf%, "}" 'not in cmem
                    ELSE
                        WriteBufLine f12Buf%, "ZeroMemory((uint8*)(" + n$ + "[0]),tmp_long*" + bytesperelement$ + ");"
                        WriteBufLine f12Buf%, "while(tmp_long--){"
                        acc$ = ""
                        initialise_array_udt_varstrings n$, udt, 0, bytesperelement$, acc$
                        WriteBufLine f12Buf%, acc$ + "}"
                    END IF

                    IF redimoption = 2 THEN
                        WriteBufLine f12Buf%, "tmp_long=preserve_copy_count;"
                        WriteBufLine f12Buf%, "while(tmp_long--){"
                        IF stringarray THEN
                            WriteBufLine f12Buf%, "qbs_set((qbs*)((uint64*)(preserve_new_ptr))[tmp_long],(qbs*)((uint64*)(preserve_old_ptr))[tmp_long]);"
                        ELSE
                            acc$ = ""
                            copy_preserve_udt_varstrings "preserve_new_ptr", "preserve_old_ptr", udt, "(tmp_long*" + bytesperelement$ + ")", "(tmp_long*" + bytesperelement$ + ")", acc$
                            WriteBufLine f12Buf%, acc$
                        END IF
                        WriteBufLine f12Buf%, "}"
                    ELSEIF redimoption = 3 THEN
                        'copy overlap region by coordinates
                        WriteBufLine f12Buf%, "if (preserve_any){"
                        FOR i = 0 TO nume - 1
                            WriteBufLine f12Buf%, "preserve_idx[" + _TOSTR$(i) + "]=preserve_lo[" + _TOSTR$(i) + "];"
                        NEXT
                        WriteBufLine f12Buf%, "for(;;){"
                        argi = (nume - 1) * 4 + 4
                        WriteBufLine f12Buf%, "preserve_old_off=preserve_idx[0]-preserve_old_desc[" + _TOSTR$(argi) + "];"
                        WriteBufLine f12Buf%, "preserve_new_off=preserve_idx[0]-alloc_new_desc[" + _TOSTR$(argi) + "];"
                        FOR i = 2 TO nume
                            argi = (nume - i) * 4 + 4
                            WriteBufLine f12Buf%, "preserve_old_off+=(preserve_idx[" + _TOSTR$(i - 1) + "]-preserve_old_desc[" + _TOSTR$(argi) + "])*preserve_old_desc[" + _TOSTR$(argi + 2) + "];"
                            WriteBufLine f12Buf%, "preserve_new_off+=(preserve_idx[" + _TOSTR$(i - 1) + "]-alloc_new_desc[" + _TOSTR$(argi) + "])*alloc_new_desc[" + _TOSTR$(argi + 2) + "];"
                        NEXT

                        IF stringarray THEN
                            WriteBufLine f12Buf%, "qbs_set((qbs*)((uint64*)(preserve_new_ptr))[preserve_new_off],(qbs*)((uint64*)(preserve_old_ptr))[preserve_old_off]);"
                        ELSE
                            acc$ = ""
                            copy_preserve_udt_varstrings "preserve_new_ptr", "preserve_old_ptr", udt, "(preserve_new_off*" + bytesperelement$ + ")", "(preserve_old_off*" + bytesperelement$ + ")", acc$
                            WriteBufLine f12Buf%, acc$
                        END IF

                        WriteBufLine f12Buf%, "preserve_dim=0;"
                        WriteBufLine f12Buf%, "while (preserve_dim<" + _TOSTR$(nume) + "){"
                        WriteBufLine f12Buf%, "preserve_idx[preserve_dim]++;"
                        WriteBufLine f12Buf%, "if (preserve_idx[preserve_dim]<=preserve_hi[preserve_dim]) break;"
                        WriteBufLine f12Buf%, "preserve_idx[preserve_dim]=preserve_lo[preserve_dim];"
                        WriteBufLine f12Buf%, "preserve_dim++;"
                        WriteBufLine f12Buf%, "}"
                        WriteBufLine f12Buf%, "if (preserve_dim==" + _TOSTR$(nume) + ") break;"
                        WriteBufLine f12Buf%, "}"
                        WriteBufLine f12Buf%, "}"
                    END IF

                    'free OLD array content and OLD raw block
                    IF stringarray THEN
                        WriteBufLine f12Buf%, "tmp_long=preserve_old_total;"
                        WriteBufLine f12Buf%, "while(tmp_long--) qbs_free((qbs*)((uint64*)(preserve_old_ptr))[tmp_long]);"
                        WriteBufLine f12Buf%, "free((void*)(preserve_old_ptr));"
                    ELSE
                        WriteBufLine f12Buf%, n$ + "[0]=preserve_old_ptr;"
                        WriteBufLine f12Buf%, "tmp_long=preserve_old_total;"
                        WriteBufLine f12Buf%, "while(tmp_long--){"
                        acc$ = ""
                        free_array_udt_varstrings n$, udt, 0, bytesperelement$, acc$
                        WriteBufLine f12Buf%, acc$ + "}"
                        WriteBufLine f12Buf%, "free((void*)(preserve_old_ptr));"
                    END IF

                    WriteBufLine f12Buf%, n$ + "[0]=preserve_new_ptr;"
                    WriteBufLine f12Buf%, "}else{"
                END IF

                '1. Create array
                WriteBufLine f12Buf%, n$ + "[0]=(ptrszint)malloc((size_t)alloc_req_bytes);"
                WriteBufLine f12Buf%, "if (!" + n$ + "[0]) error(257);" 'not enough memory
                WriteBufLine f12Buf%, n$ + "[2]|=1;" 'ADD initialized flag
                WriteBufLine f12Buf%, "tmp_long=(ptrszint)alloc_req_elems;"


                'init individual strings
                IF stringarray THEN
                    WriteBufLine f12Buf%, "if (" + n$ + "[2]&4){" 'array is in cmem
                    WriteBufLine f12Buf%, "while(tmp_long--) ((uint64*)(" + n$ + "[0]))[tmp_long]=(uint64)qbs_new_cmem(0,0);"
                    WriteBufLine f12Buf%, "}else{" 'not in cmem
                    WriteBufLine f12Buf%, "while(tmp_long--) ((uint64*)(" + n$ + "[0]))[tmp_long]=(uint64)qbs_new(0,0);"
                    WriteBufLine f12Buf%, "}" 'not in cmem
                ELSE 'initialise udt's
                    WriteBufLine f12Buf%, "ZeroMemory((uint8*)(" + n$ + "[0]),tmp_long*" + bytesperelement$ + ");"
                    WriteBufLine f12Buf%, "while(tmp_long--){"
                    acc$ = ""
                    initialise_array_udt_varstrings n$, udt, 0, bytesperelement$, acc$
                    WriteBufLine f12Buf%, acc$ + "}"
                END IF

                IF redimoption THEN
                    WriteBufLine f12Buf%, "}"
                END IF


                '2. Generate "clean up" code (called when EXITING A SUB/FUNCTION)
                IF arraydesc = 0 THEN 'only add for first declaration of the array
                    WriteBufLine FreeTxtBuf, "if (" + n$ + "[2]&1){" 'initialized?
                    WriteBufLine FreeTxtBuf, "tmp_long=" + elesizestr$ + ";"
                    IF udt > 0 AND udtxvariable(udt) THEN
                        WriteBufLine FreeTxtBuf, "while(tmp_long--) {"
                        acc$ = ""
                        free_array_udt_varstrings n$, udt, 0, bytesperelement$, acc$
                        WriteBufLine FreeTxtBuf, acc$ + "}"
                    ELSE
                        WriteBufLine FreeTxtBuf, "while(tmp_long--) qbs_free((qbs*)((uint64*)(" + n$ + "[0]))[tmp_long]);"
                    END IF
                    WriteBufLine FreeTxtBuf, "free((void*)(" + n$ + "[0]));"
                    WriteBufLine FreeTxtBuf, "}"
                    'free lock (_MEM)
                    WriteBufLine FreeTxtBuf, "free_mem_lock( (mem_lock*)((ptrszint*)" + n$ + ")[" + _TOSTR$(4 * nume + 4 + 1 - 1) + "] );"
                END IF


            ELSE 'not string/var-udt array

                '1. Create array
                WriteBufLine f12Buf%, "if (" + n$ + "[2]&4){" 'array will be in cmem

                IF redimoption THEN
                    WriteBufLine f12Buf%, "if (preserve_old_total){"
                    WriteBufLine f12Buf%, "preserve_new_ptr=(ptrszint)cmem_dynamic_malloc((size_t)alloc_req_bytes);"
                    WriteBufLine f12Buf%, "if (!preserve_new_ptr) error(257);"
                    WriteBufLine f12Buf%, "memset((void*)(preserve_new_ptr),0,(size_t)alloc_req_bytes);"
                    IF redimoption = 2 THEN
                        WriteBufLine f12Buf%, "if (preserve_copy_count) memcpy((void*)(preserve_new_ptr),(void*)(preserve_old_ptr),preserve_copy_count*" + bytesperelement$ + ");"
                    ELSEIF redimoption = 3 THEN
                        WriteBufLine f12Buf%, "if (preserve_any){"
                        FOR i = 0 TO nume - 1
                            WriteBufLine f12Buf%, "preserve_idx[" + _TOSTR$(i) + "]=preserve_lo[" + _TOSTR$(i) + "];"
                        NEXT
                        WriteBufLine f12Buf%, "for(;;){"
                        argi = (nume - 1) * 4 + 4
                        WriteBufLine f12Buf%, "preserve_old_off=preserve_idx[0]-preserve_old_desc[" + _TOSTR$(argi) + "];"
                        WriteBufLine f12Buf%, "preserve_new_off=preserve_idx[0]-alloc_new_desc[" + _TOSTR$(argi) + "];"
                        FOR i = 2 TO nume
                            argi = (nume - i) * 4 + 4
                            WriteBufLine f12Buf%, "preserve_old_off+=(preserve_idx[" + _TOSTR$(i - 1) + "]-preserve_old_desc[" + _TOSTR$(argi) + "])*preserve_old_desc[" + _TOSTR$(argi + 2) + "];"
                            WriteBufLine f12Buf%, "preserve_new_off+=(preserve_idx[" + _TOSTR$(i - 1) + "]-alloc_new_desc[" + _TOSTR$(argi) + "])*alloc_new_desc[" + _TOSTR$(argi + 2) + "];"
                        NEXT
                        WriteBufLine f12Buf%, "memcpy(((uint8*)(preserve_new_ptr))+preserve_new_off*" + bytesperelement$ + ",((uint8*)(preserve_old_ptr))+preserve_old_off*" + bytesperelement$ + "," + bytesperelement$ + ");"
                        WriteBufLine f12Buf%, "preserve_dim=0;"
                        WriteBufLine f12Buf%, "while (preserve_dim<" + _TOSTR$(nume) + "){"
                        WriteBufLine f12Buf%, "preserve_idx[preserve_dim]++;"
                        WriteBufLine f12Buf%, "if (preserve_idx[preserve_dim]<=preserve_hi[preserve_dim]) break;"
                        WriteBufLine f12Buf%, "preserve_idx[preserve_dim]=preserve_lo[preserve_dim];"
                        WriteBufLine f12Buf%, "preserve_dim++;"
                        WriteBufLine f12Buf%, "}"
                        WriteBufLine f12Buf%, "if (preserve_dim==" + _TOSTR$(nume) + ") break;"
                        WriteBufLine f12Buf%, "}"
                        WriteBufLine f12Buf%, "}"
                    END IF
                    IF udt > 0 AND dynarrmode <> 0 AND UDTDynHasMemberArrays%(udt, dynarrmode) THEN
                        ' REDIM/_PRESERVE/_RETAIN over descriptor-layout UDT arrays cannot use a raw
                        ' byte copy. Initialize the new descriptor graph, deep-copy the preserved
                        ' intersection, then free the old descriptor graph before releasing old data.
                        WriteBufLine f12Buf%, "if (preserve_old_flags&8){"
                        IF redimoption > 1 THEN
                            WriteBufLine f12Buf%, n$ + "[0]=preserve_new_ptr;"
                            WriteBufLine f12Buf%, n$ + "[2]|=8;"
                            WriteBufLine f12Buf%, "tmp_long=(ptrszint)alloc_req_elems;"
                            WriteBufLine f12Buf%, "while(tmp_long--){"
                            acc$ = ""
                            AppendDynUDTDescInit n$, udt, 0, bytesperelement$, acc$, dynarrmode
                            IF Error_Happened THEN EXIT FUNCTION
                            WriteBufLine f12Buf%, acc$
                            WriteBufLine f12Buf%, "}"
                            IF redimoption = 2 THEN
                                WriteBufLine f12Buf%, "tmp_long=(ptrszint)preserve_copy_count;"
                                WriteBufLine f12Buf%, "while(tmp_long--){"
                                acc$ = ""
                                AppendDynUDTDescCopy "preserve_new_ptr", "preserve_old_ptr", udt, "(tmp_long*" + bytesperelement$ + ")", "(tmp_long*" + bytesperelement$ + ")", bytesperelement$, acc$, dynarrmode
                                IF Error_Happened THEN EXIT FUNCTION
                                WriteBufLine f12Buf%, acc$
                                WriteBufLine f12Buf%, "}"
                            ELSEIF redimoption = 3 THEN
                                WriteBufLine f12Buf%, "if (preserve_any){"
                                FOR i = 0 TO nume - 1
                                    WriteBufLine f12Buf%, "preserve_idx[" + _TOSTR$(i) + "]=preserve_lo[" + _TOSTR$(i) + "];"
                                NEXT
                                WriteBufLine f12Buf%, "for(;;){"
                                argi = (nume - 1) * 4 + 4
                                WriteBufLine f12Buf%, "preserve_old_off=preserve_idx[0]-preserve_old_desc[" + _TOSTR$(argi) + "];"
                                WriteBufLine f12Buf%, "preserve_new_off=preserve_idx[0]-alloc_new_desc[" + _TOSTR$(argi) + "];"
                                FOR i = 2 TO nume
                                    argi = (nume - i) * 4 + 4
                                    WriteBufLine f12Buf%, "preserve_old_off+=(preserve_idx[" + _TOSTR$(i - 1) + "]-preserve_old_desc[" + _TOSTR$(argi) + "])*preserve_old_desc[" + _TOSTR$(argi + 2) + "];"
                                    WriteBufLine f12Buf%, "preserve_new_off+=(preserve_idx[" + _TOSTR$(i - 1) + "]-alloc_new_desc[" + _TOSTR$(argi) + "])*alloc_new_desc[" + _TOSTR$(argi + 2) + "];"
                                NEXT
                                acc$ = ""
                                AppendDynUDTDescCopy "preserve_new_ptr", "preserve_old_ptr", udt, "(preserve_new_off*" + bytesperelement$ + ")", "(preserve_old_off*" + bytesperelement$ + ")", bytesperelement$, acc$, dynarrmode
                                IF Error_Happened THEN EXIT FUNCTION
                                WriteBufLine f12Buf%, acc$
                                WriteBufLine f12Buf%, "preserve_dim=0;"
                                WriteBufLine f12Buf%, "while (preserve_dim<" + _TOSTR$(nume) + "){"
                                WriteBufLine f12Buf%, "preserve_idx[preserve_dim]++;"
                                WriteBufLine f12Buf%, "if (preserve_idx[preserve_dim]<=preserve_hi[preserve_dim]) break;"
                                WriteBufLine f12Buf%, "preserve_idx[preserve_dim]=preserve_lo[preserve_dim];"
                                WriteBufLine f12Buf%, "preserve_dim++;"
                                WriteBufLine f12Buf%, "}"
                                WriteBufLine f12Buf%, "if (preserve_dim==" + _TOSTR$(nume) + ") break;"
                                WriteBufLine f12Buf%, "}"
                                WriteBufLine f12Buf%, "}"
                            END IF
                        END IF
                        WriteBufLine f12Buf%, "tmp_long=(ptrszint)preserve_old_total;"
                        WriteBufLine f12Buf%, "while(tmp_long--){"
                        acc$ = ""
                        AppendDynUDTDescFree "preserve_old_ptr", udt, 0, bytesperelement$, acc$, dynarrmode
                        IF Error_Happened THEN EXIT FUNCTION
                        WriteBufLine f12Buf%, acc$
                        WriteBufLine f12Buf%, "}"
                        WriteBufLine f12Buf%, "}"
                    END IF
                    WriteBufLine f12Buf%, "if (preserve_old_flags&4){"
                    WriteBufLine f12Buf%, "cmem_dynamic_free((uint8*)(preserve_old_ptr));"
                    WriteBufLine f12Buf%, "}else{"
                    WriteBufLine f12Buf%, "free((void*)(preserve_old_ptr));"
                    WriteBufLine f12Buf%, "}"
                    WriteBufLine f12Buf%, n$ + "[0]=preserve_new_ptr;"
                    WriteBufLine f12Buf%, "}else{"
                END IF

                'standard cmem method
                WriteBufLine f12Buf%, n$ + "[0]=(ptrszint)cmem_dynamic_malloc((size_t)alloc_req_bytes);"
                WriteBufLine f12Buf%, "if (!" + n$ + "[0]) error(257);"
                WriteBufLine f12Buf%, "memset((void*)(" + n$ + "[0]),0,(size_t)alloc_req_bytes);"

                IF redimoption THEN
                    WriteBufLine f12Buf%, "}"
                END IF

                WriteBufLine f12Buf%, "}else{" 'not in cmem

                IF redimoption THEN
                    WriteBufLine f12Buf%, "if (preserve_old_total){"
                    WriteBufLine f12Buf%, "preserve_new_ptr=(ptrszint)calloc((size_t)alloc_req_bytes,1);"
                    WriteBufLine f12Buf%, "if (!preserve_new_ptr) error(257);"
                    IF redimoption = 2 THEN
                        WriteBufLine f12Buf%, "if (preserve_copy_count) memcpy((void*)(preserve_new_ptr),(void*)(preserve_old_ptr),preserve_copy_count*" + bytesperelement$ + ");"
                    ELSEIF redimoption = 3 THEN
                        WriteBufLine f12Buf%, "if (preserve_any){"
                        FOR i = 0 TO nume - 1
                            WriteBufLine f12Buf%, "preserve_idx[" + _TOSTR$(i) + "]=preserve_lo[" + _TOSTR$(i) + "];"
                        NEXT
                        WriteBufLine f12Buf%, "for(;;){"
                        argi = (nume - 1) * 4 + 4
                        WriteBufLine f12Buf%, "preserve_old_off=preserve_idx[0]-preserve_old_desc[" + _TOSTR$(argi) + "];"
                        WriteBufLine f12Buf%, "preserve_new_off=preserve_idx[0]-alloc_new_desc[" + _TOSTR$(argi) + "];"
                        FOR i = 2 TO nume
                            argi = (nume - i) * 4 + 4
                            WriteBufLine f12Buf%, "preserve_old_off+=(preserve_idx[" + _TOSTR$(i - 1) + "]-preserve_old_desc[" + _TOSTR$(argi) + "])*preserve_old_desc[" + _TOSTR$(argi + 2) + "];"
                            WriteBufLine f12Buf%, "preserve_new_off+=(preserve_idx[" + _TOSTR$(i - 1) + "]-alloc_new_desc[" + _TOSTR$(argi) + "])*alloc_new_desc[" + _TOSTR$(argi + 2) + "];"
                        NEXT
                        WriteBufLine f12Buf%, "memcpy(((uint8*)(preserve_new_ptr))+preserve_new_off*" + bytesperelement$ + ",((uint8*)(preserve_old_ptr))+preserve_old_off*" + bytesperelement$ + "," + bytesperelement$ + ");"
                        WriteBufLine f12Buf%, "preserve_dim=0;"
                        WriteBufLine f12Buf%, "while (preserve_dim<" + _TOSTR$(nume) + "){"
                        WriteBufLine f12Buf%, "preserve_idx[preserve_dim]++;"
                        WriteBufLine f12Buf%, "if (preserve_idx[preserve_dim]<=preserve_hi[preserve_dim]) break;"
                        WriteBufLine f12Buf%, "preserve_idx[preserve_dim]=preserve_lo[preserve_dim];"
                        WriteBufLine f12Buf%, "preserve_dim++;"
                        WriteBufLine f12Buf%, "}"
                        WriteBufLine f12Buf%, "if (preserve_dim==" + _TOSTR$(nume) + ") break;"
                        WriteBufLine f12Buf%, "}"
                        WriteBufLine f12Buf%, "}"
                    END IF
                    IF udt > 0 AND dynarrmode <> 0 AND UDTDynHasMemberArrays%(udt, dynarrmode) THEN
                        WriteBufLine f12Buf%, "if (preserve_old_flags&8){"
                        IF redimoption > 1 THEN
                            WriteBufLine f12Buf%, n$ + "[0]=preserve_new_ptr;"
                            WriteBufLine f12Buf%, n$ + "[2]|=8;"
                            WriteBufLine f12Buf%, "tmp_long=(ptrszint)alloc_req_elems;"
                            WriteBufLine f12Buf%, "while(tmp_long--){"
                            acc$ = ""
                            AppendDynUDTDescInit n$, udt, 0, bytesperelement$, acc$, dynarrmode
                            IF Error_Happened THEN EXIT FUNCTION
                            WriteBufLine f12Buf%, acc$
                            WriteBufLine f12Buf%, "}"
                            IF redimoption = 2 THEN
                                WriteBufLine f12Buf%, "tmp_long=(ptrszint)preserve_copy_count;"
                                WriteBufLine f12Buf%, "while(tmp_long--){"
                                acc$ = ""
                                AppendDynUDTDescCopy "preserve_new_ptr", "preserve_old_ptr", udt, "(tmp_long*" + bytesperelement$ + ")", "(tmp_long*" + bytesperelement$ + ")", bytesperelement$, acc$, dynarrmode
                                IF Error_Happened THEN EXIT FUNCTION
                                WriteBufLine f12Buf%, acc$
                                WriteBufLine f12Buf%, "}"
                            ELSEIF redimoption = 3 THEN
                                WriteBufLine f12Buf%, "if (preserve_any){"
                                FOR i = 0 TO nume - 1
                                    WriteBufLine f12Buf%, "preserve_idx[" + _TOSTR$(i) + "]=preserve_lo[" + _TOSTR$(i) + "];"
                                NEXT
                                WriteBufLine f12Buf%, "for(;;){"
                                argi = (nume - 1) * 4 + 4
                                WriteBufLine f12Buf%, "preserve_old_off=preserve_idx[0]-preserve_old_desc[" + _TOSTR$(argi) + "];"
                                WriteBufLine f12Buf%, "preserve_new_off=preserve_idx[0]-alloc_new_desc[" + _TOSTR$(argi) + "];"
                                FOR i = 2 TO nume
                                    argi = (nume - i) * 4 + 4
                                    WriteBufLine f12Buf%, "preserve_old_off+=(preserve_idx[" + _TOSTR$(i - 1) + "]-preserve_old_desc[" + _TOSTR$(argi) + "])*preserve_old_desc[" + _TOSTR$(argi + 2) + "];"
                                    WriteBufLine f12Buf%, "preserve_new_off+=(preserve_idx[" + _TOSTR$(i - 1) + "]-alloc_new_desc[" + _TOSTR$(argi) + "])*alloc_new_desc[" + _TOSTR$(argi + 2) + "];"
                                NEXT
                                acc$ = ""
                                AppendDynUDTDescCopy "preserve_new_ptr", "preserve_old_ptr", udt, "(preserve_new_off*" + bytesperelement$ + ")", "(preserve_old_off*" + bytesperelement$ + ")", bytesperelement$, acc$, dynarrmode
                                IF Error_Happened THEN EXIT FUNCTION
                                WriteBufLine f12Buf%, acc$
                                WriteBufLine f12Buf%, "preserve_dim=0;"
                                WriteBufLine f12Buf%, "while (preserve_dim<" + _TOSTR$(nume) + "){"
                                WriteBufLine f12Buf%, "preserve_idx[preserve_dim]++;"
                                WriteBufLine f12Buf%, "if (preserve_idx[preserve_dim]<=preserve_hi[preserve_dim]) break;"
                                WriteBufLine f12Buf%, "preserve_idx[preserve_dim]=preserve_lo[preserve_dim];"
                                WriteBufLine f12Buf%, "preserve_dim++;"
                                WriteBufLine f12Buf%, "}"
                                WriteBufLine f12Buf%, "if (preserve_dim==" + _TOSTR$(nume) + ") break;"
                                WriteBufLine f12Buf%, "}"
                                WriteBufLine f12Buf%, "}"
                            END IF
                        END IF
                        WriteBufLine f12Buf%, "tmp_long=(ptrszint)preserve_old_total;"
                        WriteBufLine f12Buf%, "while(tmp_long--){"
                        acc$ = ""
                        AppendDynUDTDescFree "preserve_old_ptr", udt, 0, bytesperelement$, acc$, dynarrmode
                        IF Error_Happened THEN EXIT FUNCTION
                        WriteBufLine f12Buf%, acc$
                        WriteBufLine f12Buf%, "}"
                        WriteBufLine f12Buf%, "}"
                    END IF
                    WriteBufLine f12Buf%, "if (preserve_old_flags&4){"
                    WriteBufLine f12Buf%, "cmem_dynamic_free((uint8*)(preserve_old_ptr));"
                    WriteBufLine f12Buf%, "}else{"
                    WriteBufLine f12Buf%, "free((void*)(preserve_old_ptr));"
                    WriteBufLine f12Buf%, "}"
                    WriteBufLine f12Buf%, n$ + "[0]=preserve_new_ptr;"
                    WriteBufLine f12Buf%, "}else{"
                END IF
                'standard allocation method
                WriteBufLine f12Buf%, n$ + "[0]=(ptrszint)calloc((size_t)alloc_req_bytes,1);"
                WriteBufLine f12Buf%, "if (!" + n$ + "[0]) error(257);" 'not enough memory
                IF redimoption THEN
                    WriteBufLine f12Buf%, "}"
                END IF


                WriteBufLine f12Buf%, "}" 'not in cmem
                WriteBufLine f12Buf%, n$ + "[2]|=1;" 'ADD initialized flag

                IF udt > 0 AND dynarrmode <> 0 THEN
                    IF UDTDynHasMemberArrays%(udt, dynarrmode) THEN
                        ' Fresh dynamic allocation path: descriptors are initialized only once after
                        ' the raw array payload exists. Do not also initialize in the REDIM capture
                        ' path, or ordinary REDIM leaks/double-initializes member descriptors.
                        WriteBufLine f12Buf%, n$ + "[2]|=8;" 'dynamic UDT descriptor-layout flag
                        IF redimoption > 1 THEN WriteBufLine f12Buf%, "if (!(preserve_old_total&&(preserve_old_flags&8))){"
                        WriteBufLine f12Buf%, "tmp_long=(ptrszint)alloc_req_elems;"
                        WriteBufLine f12Buf%, "while(tmp_long--){"
                        acc$ = ""
                        AppendDynUDTDescInit n$, udt, 0, bytesperelement$, acc$, dynarrmode
                        IF Error_Happened THEN EXIT FUNCTION
                        WriteBufLine f12Buf%, acc$
                        WriteBufLine f12Buf%, "}"
                        IF redimoption > 1 THEN WriteBufLine f12Buf%, "}"
                    END IF
                END IF

                '2. Generate "clean up" code (called when EXITING A SUB/FUNCTION)
                IF arraydesc = 0 THEN 'only add for first declaration of the array
                    WriteBufLine FreeTxtBuf, "if (" + n$ + "[2]&1){" 'initialized?
                    IF udt > 0 AND dynarrmode <> 0 AND UDTDynHasMemberArrays%(udt, dynarrmode) THEN
                        ' Scope-exit cleanup for descriptor-layout UDT arrays must walk every parent
                        ' element and free its owned member descriptors before the parent data block
                        ' itself is released below.
                        WriteBufLine FreeTxtBuf, "if (" + n$ + "[2]&8){"
                        WriteBufLine FreeTxtBuf, "tmp_long=" + elesizestr$ + ";"
                        WriteBufLine FreeTxtBuf, "while(tmp_long--){"
                        acc$ = ""
                        AppendDynUDTDescFree n$ + "[0]", udt, 0, bytesperelement$, acc$, dynarrmode
                        IF Error_Happened THEN EXIT FUNCTION
                        WriteBufLine FreeTxtBuf, acc$
                        WriteBufLine FreeTxtBuf, "}"
                        WriteBufLine FreeTxtBuf, "}"
                    END IF
                    WriteBufLine FreeTxtBuf, "if (" + n$ + "[2]&4){" 'array is in cmem
                    WriteBufLine FreeTxtBuf, "cmem_dynamic_free((uint8*)(" + n$ + "[0]));"
                    WriteBufLine FreeTxtBuf, "}else{"
                    WriteBufLine FreeTxtBuf, "free((void*)(" + n$ + "[0]));"
                    WriteBufLine FreeTxtBuf, "}" 'cmem
                    WriteBufLine FreeTxtBuf, "}" 'init
                    'free lock (_MEM)
                    WriteBufLine FreeTxtBuf, "free_mem_lock( (mem_lock*)((ptrszint*)" + n$ + ")[" + _TOSTR$(4 * nume + 4 + 1 - 1) + "] );"
                END IF
            END IF 'not string array

            WriteBufLine f12Buf%, commitdesc$

        END IF 'undefined=0

        '----FINISH ARRAY DESCRIPTOR IF DEFINING FOR THE FIRST TIME----
        IF arraydesc = 0 THEN
            'Note: Array is init as undefined (& possibly a cmem flag)
            IF cmem THEN WriteBufLine DataTxtBuf, n$ + "[2]=4;" ELSE WriteBufLine DataTxtBuf, n$ + "[2]=0;"
            'set dimensions as undefined
            FOR i = 1 TO nume
                b = i * 4
                WriteBufLine DataTxtBuf, n$ + "[" + _TOSTR$(b) + "]=2147483647;" 'base
                WriteBufLine DataTxtBuf, n$ + "[" + _TOSTR$(b + 1) + "]=0;" 'num. index
                WriteBufLine DataTxtBuf, n$ + "[" + _TOSTR$(b + 2) + "]=0;" 'multiplier
            NEXT
            IF stringarray THEN
                'set array's data offset to the offset of the offset to nothingstring
                WriteBufLine DataTxtBuf, n$ + "[0]=(ptrszint)&nothingstring;"
            ELSE
                'set array's data offset to "nothing"
                WriteBufLine DataTxtBuf, n$ + "[0]=(ptrszint)nothingvalue;"
            END IF
            WriteBufLine DataTxtBuf, "}" 'close array descriptor
        END IF 'arraydesc = 0

        IF undefined = 0 THEN

            IF redimoption = 0 THEN WriteBufLine f12Buf%, "}" 'if REDIM not specified the above is conditional
            WriteBufLine f12Buf%, "}" 'not static

        END IF 'undefined=0

        allocarray = nume
        IF undefined = -1 THEN allocarray = -1

    END IF

    IF autoary = 0 THEN
        IF dimoption = 3 THEN 'STATIC a(100) puts creation code in main
            BufInsertBuf DataTxtBuf, f12Buf% 'insert accumulated code into target buffer
        ELSE
            BufInsertBuf MainTxtBuf, f12Buf% 'insert accumulated code into target buffer
        END IF
    END IF

    '[8] offset of data
    '[8] reserved (could be used to store a bit offset)
    '(the following repeats depending on the number of elements)
    '[4] base-offset
    '[4] number of indexes
    '[4] multiplier (the last multiplier doesn't actually exist)
    '[4] reserved

    DisposeBuf f12Buf% 'destroy and free temporary buffer

    dimshared = dimsharedlast

    tlayout$ = l$
END FUNCTION

FUNCTION arrayreference$ (indexes$, typ)
    arrayprocessinghappened = 1
    '*returns an array reference: idnumber | index$
    '*does not take into consideration the type of the array

    '*expects array id to be passed in the global id structure





    idnumber$ = _TOSTR$(currentid)

    DIM id2 AS idstruct

    id2 = id

    a$ = indexes$
    typ = id2.arraytype + ISARRAY + ISREFERENCE
    n$ = RTRIM$(id2.callname)

    IF a$ = "" THEN 'no indexes passed eg. a()
        r$ = "0"
        GOTO gotarrayindex
    END IF

    n = numelements(a$)

    'find number of elements supplied
    elements = 1
    b = 0
    FOR i = 1 TO n
        a = ASC(getelement(a$, i))
        IF a = 40 THEN b = b + 1
        IF a = 41 THEN b = b - 1
        IF a = 44 AND b = 0 THEN elements = elements + 1
    NEXT

    IF id2.arrayelements = -1 THEN
        IF arrayelementslist(currentid) <> 0 AND elements <> arrayelementslist(currentid) THEN Give_Error "Cannot change the number of elements an array has!": EXIT FUNCTION
        IF elements = 1 THEN id2.arrayelements = 1: ids(currentid).arrayelements = 1 'lucky guess
        arrayelementslist(currentid) = elements
    ELSE
        IF elements <> id2.arrayelements THEN Give_Error "Cannot change the number of elements an array has!": EXIT FUNCTION
    END IF

    curarg = 1
    firsti = 1
    FOR i = 1 TO n
        l$ = getelement(a$, i)
        IF l$ = "(" THEN b = b + 1
        IF l$ = ")" THEN b = b - 1
        IF (l$ = "," AND b = 0) OR (i = n) THEN
            IF i = n THEN
                IF l$ = "," THEN Give_Error "Array index missing": EXIT FUNCTION
                e$ = evaluatetotyp(getelements$(a$, firsti, i), 64&)
                IF Error_Happened THEN EXIT FUNCTION
            ELSE
                e$ = evaluatetotyp(getelements$(a$, firsti, i - 1), 64&)
                IF Error_Happened THEN EXIT FUNCTION
            END IF
            IF e$ = "" THEN Give_Error "Array index missing": EXIT FUNCTION
            argi = (elements - curarg) * 4 + 4
            IF curarg = 1 THEN
                IF CheckingOn THEN
                    r$ = r$ + "array_check((" + e$ + ")-" + n$ + "[" + _TOSTR$(argi) + "]," + n$ + "[" + _TOSTR$(argi + 1) + "])+"
                ELSE
                    r$ = r$ + "(" + e$ + ")-" + n$ + "[" + _TOSTR$(argi) + "]+"
                END IF

            ELSE
                IF CheckingOn THEN
                    r$ = r$ + "array_check((" + e$ + ")-" + n$ + "[" + _TOSTR$(argi) + "]," + n$ + "[" + _TOSTR$(argi + 1) + "])*" + n$ + "[" + _TOSTR$(argi + 2) + "]+"
                ELSE
                    r$ = r$ + "((" + e$ + ")-" + n$ + "[" + _TOSTR$(argi) + "])*" + n$ + "[" + _TOSTR$(argi + 2) + "]+"
                END IF
            END IF
            firsti = i + 1
            curarg = curarg + 1
        END IF
    NEXT
    r$ = LEFT$(r$, LEN(r$) - 1) 'remove trailing +
    gotarrayindex:

    r$ = idnumber$ + sp3 + r$
    arrayreference$ = r$
    'PRINT "arrayreference returning:" + r$

END FUNCTION



'Helpers for working with udtearraydesc().
'
'udtearraydesc() stores serialized declaration-time lower/count pairs for every TYPE
'member array. Inline members use them as fixed layout metadata; explicit _Dynamic
'members use them as the initial bounds for their live runtime descriptor.
'
'Descriptor grammar:
'
'    descriptor := diminfo (";" diminfo)*
'    diminfo    := lower "," count
'
'where:
'
'    lower = signed decimal lower bound of the dimension
'    count = positive decimal element count of the dimension
'
'Important:
'  - The descriptor stores counts, not upper bounds.
'  - upper_bound = lower + count - 1
'  - Dimensions are stored in source order.
'  - This string is compiler metadata for inline and _Dynamic member arrays. It is
'    not itself a QB64 runtime array descriptor.
'
'Examples:
'
'    a(0 TO 3)              -> "0,4"
'    b(1 TO 10)             -> "1,10"
'    c(-2 TO 2, 5 TO 7)     -> "-2,5;5,3"
'
'Main helper roles:
FUNCTION UDTFieldModeToken% (token AS STRING)
    SELECT CASE UCASE$(token)
        CASE "_STATIC"
            UDTFieldModeToken% = 1
        CASE "_DYNAMIC"
            UDTFieldModeToken% = 2
    END SELECT
END FUNCTION

SUB UDTApplyFieldMode (token AS STRING, fieldmode AS LONG)
    DIM parsed_mode AS LONG

    parsed_mode = UDTFieldModeToken%(token)
    IF parsed_mode = 0 THEN EXIT SUB
    IF unstableFlags(UNSTABLE_TYPEFIELDS) = 0 THEN
        Give_Error "_Static/_Dynamic require $Unstable:TypeFields"
        EXIT SUB
    END IF
    IF fieldmode <> 0 THEN
        Give_Error "A TYPE member array cannot use both _Dynamic and _Static"
        EXIT SUB
    END IF
    fieldmode = parsed_mode
END SUB

FUNCTION UDTFieldModeLayout$ (fieldmode AS LONG)
    SELECT CASE fieldmode
        CASE 1
            UDTFieldModeLayout$ = SCase2$("_Static")
        CASE 2
            UDTFieldModeLayout$ = SCase2$("_Dynamic")
    END SELECT
END FUNCTION

'Central decision point for whether a TYPE member array is physically stored as
'a descriptor slot. Explicit _Dynamic uses descriptor storage; explicit _Static
'and unmarked compile-time member arrays remain inline for compatibility.
FUNCTION UDTMemberDynDesc% (member_id AS LONG)
    IF member_id <= 0 THEN EXIT FUNCTION
    IF udtearrayelements(member_id) = 0 THEN EXIT FUNCTION
    IF udtearrayfieldmode(member_id) = 2 THEN UDTMemberDynDesc% = -1
END FUNCTION

FUNCTION UDTDynMemberOffset& (member_id AS LONG)
    UDTDynMemberOffset& = udtefdynoffset(member_id)
END FUNCTION

FUNCTION UDTDynMemberSize& (member_id AS LONG)
    UDTDynMemberSize& = udtefdynsize(member_id)
END FUNCTION

FUNCTION UDTDynLayoutSize& (udt_index AS LONG)
    UDTDynLayoutSize& = udtxfdynsize(udt_index)
END FUNCTION

'Return true when this TYPE graph contains an explicit _Dynamic member array.
'Unmarked and explicit _Static member arrays remain inline.
FUNCTION UDTForcedDynMembers% (udt_index AS LONG)
    DIM member_id AS LONG
    DIM nested_udt AS LONG

    member_id = udtxnext(udt_index)
    DO WHILE member_id
        IF udtearrayelements(member_id) THEN
            IF udtearrayfieldmode(member_id) = 2 THEN UDTForcedDynMembers% = -1: EXIT FUNCTION
        END IF
        IF (udtetype(member_id) AND ISUDT) <> 0 THEN
            nested_udt = udtetype(member_id) AND UDTMASK
            IF UDTForcedDynMembers%(nested_udt) THEN UDTForcedDynMembers% = -1: EXIT FUNCTION
        END IF
        member_id = udtenext(member_id)
    LOOP
END FUNCTION

'  ParseNextUDTArrayDescriptorDim()
'      Implemented in type.bas; reads one lower/count pair from the serialized metadata.
'
'  ParseUDTArrayBounds()
'      Parses TYPE member array bounds using the current global OPTION BASE and
'      builds the descriptor string plus aggregate metadata.
'
'  UDTArrayIndexExpr()
'      Builds the linearized element offset expression for inline TYPE member arrays.
'
'  UDTArrayBoundExpr()
'      Builds LBOUND/UBOUND expressions directly from the descriptor metadata.



'Preserves the original ParseUDTArrayBounds() behavior for existing callers that should
'use the current compiler OPTION BASE state.
FUNCTION ParseUDTArrayBounds& (indexes$, lower_bound AS LONG, element_count AS LONG, dimension_count AS LONG, descriptor$)
    ParseUDTArrayBounds = ParseUDTArrayBoundsEx(indexes$, optionbase, lower_bound, element_count, dimension_count, descriptor$)
END FUNCTION

'Extended helper that accepts the effective OPTION BASE explicitly.
'Why the new parameter exists:
'  TYPE member arrays are parsed during the preprocessing pass, before the main
'  compiler pass updates the global OPTION BASE state. Passing the effective
'  source-order OPTION BASE keeps classic TYPE member arrays and normal arrays
'  aligned without changing existing ParseUDTArrayBounds() callers.
FUNCTION ParseUDTArrayBoundsEx& (indexes$, effective_optionbase AS LONG, lower_bound AS LONG, element_count AS LONG, dimension_count AS LONG, descriptor$)
    DIM udt_lower_num AS ParseNum
    DIM udt_upper_num AS ParseNum

    n = numelements(indexes$)
    IF n = 0 THEN Give_Error "Array bounds missing": EXIT FUNCTION

    lower_bound = 0
    element_count = 1
    dimension_count = 0
    descriptor$ = ""

    b = 0
    firsti = 1
    FOR i = 1 TO n
        e$ = getelement$(indexes$, i)
        IF e$ = "(" THEN b = b + 1
        IF e$ = ")" THEN b = b - 1
        IF b < 0 THEN Give_Error "Invalid array bounds": EXIT FUNCTION
        IF (b = 0 AND e$ = ",") OR i = n THEN
            IF i = n THEN
                dim_expr$ = getelements$(indexes$, firsti, i)
            ELSE
                dim_expr$ = getelements$(indexes$, firsti, i - 1)
            END IF
            IF dim_expr$ = "" THEN Give_Error "Invalid array bounds": EXIT FUNCTION

            dn = numelements(dim_expr$)
            to_pos = 0
            b2 = 0
            FOR di = 1 TO dn
                e2$ = getelement$(dim_expr$, di)
                IF e2$ = "(" THEN b2 = b2 + 1
                IF e2$ = ")" THEN b2 = b2 - 1
                IF b2 < 0 THEN Give_Error "Invalid array bounds": EXIT FUNCTION
                IF b2 = 0 AND UCASE$(e2$) = "TO" THEN
                    IF to_pos THEN Give_Error "Invalid array bounds": EXIT FUNCTION
                    to_pos = di
                END IF
            NEXT
            IF b2 <> 0 THEN Give_Error "Invalid array bounds": EXIT FUNCTION

            IF to_pos THEN
                lower_expr$ = getelements$(dim_expr$, 1, to_pos - 1)
                upper_expr$ = getelements$(dim_expr$, to_pos + 1, dn)
                IF lower_expr$ = "" OR upper_expr$ = "" THEN Give_Error "Invalid array bounds": EXIT FUNCTION
            ELSE
                lower_expr$ = _TOSTR$(effective_optionbase + 0)
                upper_expr$ = dim_expr$
            END IF

            lower_const = 0
            upper_const = 0

            ' TYPE declarations are parsed in the preprocessing pass. Use the pure
            ' constant-expression evaluator here because TYPE member-array bounds
            ' must be numeric constants and are serialized as compile-time metadata.
            lower_txt$ = _TRIM$(Evaluate_Expression$(lower_expr$, udt_lower_num))
            IF LEFT$(lower_txt$, 8) = "ERROR - " THEN
                lower_txt$ = lower_expr$
            ELSEIF (udt_lower_num.typ AND ISSTRING) = 0 THEN
                lower_const = -1
            ELSE
                lower_txt$ = lower_expr$
            END IF

            upper_txt$ = _TRIM$(Evaluate_Expression$(upper_expr$, udt_upper_num))
            IF LEFT$(upper_txt$, 8) = "ERROR - " THEN
                upper_txt$ = upper_expr$
            ELSEIF (udt_upper_num.typ AND ISSTRING) = 0 THEN
                upper_const = -1
            ELSE
                upper_txt$ = upper_expr$
            END IF

            IF (lower_const AND upper_const) = 0 THEN
                Give_Error "TYPE member array bounds must be numeric constant"
                EXIT FUNCTION
            END IF

            dim_lower = VAL(lower_txt$)
            dim_upper = VAL(upper_txt$)
            IF dim_upper < dim_lower THEN Give_Error "Invalid array bounds": EXIT FUNCTION

            dim_elements = dim_upper - dim_lower + 1
            IF dim_elements <= 0 THEN Give_Error "Invalid array bounds": EXIT FUNCTION

            dim_lower_txt$ = LTRIM$(STR$(dim_lower))
            dim_elements_txt$ = LTRIM$(STR$(dim_elements))

            IF dimension_count = 0 THEN lower_bound = dim_lower
            IF descriptor$ <> "" THEN descriptor$ = descriptor$ + ";"
            descriptor$ = descriptor$ + dim_lower_txt$ + "," + dim_elements_txt$
            element_count = element_count * dim_elements

            dimension_count = dimension_count + 1
            firsti = i + 1
        END IF
    NEXT

    IF b <> 0 THEN Give_Error "Invalid array bounds": EXIT FUNCTION
    IF dimension_count = 0 THEN Give_Error "Array bounds missing": EXIT FUNCTION

    ParseUDTArrayBoundsEx = -1
END FUNCTION

FUNCTION BoundsHaveTopTo% (bounds AS STRING)
    DIM token AS STRING
    DIM token_index AS LONG
    DIM token_count AS LONG
    DIM token_depth AS LONG

    token_count = numelements(bounds)
    token_depth = 0
    BoundsHaveTopTo% = 0

    FOR token_index = 1 TO token_count
        token = getelement$(bounds, token_index)
        IF token = "(" THEN token_depth = token_depth + 1
        IF token = ")" THEN token_depth = token_depth - 1
        IF token_depth < 0 THEN EXIT FUNCTION
        IF token_depth = 0 AND UCASE$(token) = "TO" THEN
            BoundsHaveTopTo% = -1
            EXIT FUNCTION
        END IF
    NEXT
END FUNCTION




SUB BuildDynMemberBoundsPrep (bounds AS STRING, prep_prefix AS STRING, total_dims AS LONG, acc AS STRING)
    'Build a temporary QB array descriptor for REDIM of an explicit _Dynamic TYPE member array.
    'This is intentionally done in qb64pe.bas, from the REDIM parser path, matching
    'ordinary dynamic arrays in allocarray(). type.bas only consumes the descriptor.
    'The emitted C evaluates lower/upper bounds once, checks ptrszint range and
    'stores lower/count/stride in normal QB64 descriptor slots before allocation.
    DIM cr AS STRING
    DIM token AS STRING
    DIM dim_expr AS STRING
    DIM lower_expr AS STRING
    DIM upper_expr AS STRING
    DIM lower_ordered AS STRING
    DIM upper_ordered AS STRING
    DIM lower_text AS STRING
    DIM upper_text AS STRING
    DIM lower_name AS STRING
    DIM upper_name AS STRING
    DIM lower64_name AS STRING
    DIM upper64_name AS STRING
    DIM desc_name AS STRING
    DIM bounds_tokens AS LONG
    DIM outer_depth AS LONG
    DIM inner_depth AS LONG
    DIM first_index AS LONG
    DIM token_index AS LONG
    DIM dim_tokens AS LONG
    DIM dim_token_index AS LONG
    DIM to_position AS LONG
    DIM lower_is_const AS LONG
    DIM upper_is_const AS LONG
    DIM current_dim AS LONG
    DIM desc_slots AS LONG
    DIM desc_index AS LONG

    cr = CHR$(13) + CHR$(10)
    bounds_tokens = numelements(bounds)
    IF bounds_tokens = 0 THEN Give_Error "Array bounds missing": EXIT SUB

    outer_depth = 0
    total_dims = 1
    FOR token_index = 1 TO bounds_tokens
        token = getelement$(bounds, token_index)
        IF token = "(" THEN outer_depth = outer_depth + 1
        IF token = ")" THEN outer_depth = outer_depth - 1
        IF outer_depth < 0 THEN Give_Error "Invalid array bounds": EXIT SUB
        IF outer_depth = 0 AND token = "," THEN total_dims = total_dims + 1
    NEXT
    IF outer_depth <> 0 THEN Give_Error "Invalid array bounds": EXIT SUB

    desc_slots = 4 * total_dims + 4 + 1
    desc_name = prep_prefix + "_desc"

    acc = acc + cr + "static ptrszint " + desc_name + "[" + LTRIM$(STR$(desc_slots)) + "];"
    acc = acc + cr + desc_name + "[1]=0;"
    acc = acc + cr + desc_name + "[2]=1;"
    acc = acc + cr + desc_name + "[3]=" + LTRIM$(STR$(total_dims)) + ";"
    'Keep these scalar declarations free of C++ initializers. With $CHECKING:OFF,
    'SUB/FUNCTION bodies do not get the event-loop block that otherwise limits
    'their scope, and the standard entry guard can jump directly to exit_subfunc.
    'C++ permits that jump across uninitialized scalar declarations, but not
    'across declarations with initializers.
    acc = acc + cr + "ptrszint " + prep_prefix + "_stride;"
    acc = acc + cr + "ptrszint " + prep_prefix + "_lower;"
    acc = acc + cr + "ptrszint " + prep_prefix + "_upper;"
    acc = acc + cr + prep_prefix + "_stride=1;"
    acc = acc + cr + prep_prefix + "_lower=0;"
    acc = acc + cr + prep_prefix + "_upper=0;"

    outer_depth = 0
    first_index = 1
    current_dim = 0
    FOR token_index = 1 TO bounds_tokens
        token = getelement$(bounds, token_index)
        IF token = "(" THEN outer_depth = outer_depth + 1
        IF token = ")" THEN outer_depth = outer_depth - 1
        IF (outer_depth = 0 AND token = ",") OR token_index = bounds_tokens THEN
            IF token_index = bounds_tokens THEN
                dim_expr = getelements$(bounds, first_index, token_index)
            ELSE
                dim_expr = getelements$(bounds, first_index, token_index - 1)
            END IF
            IF dim_expr = "" THEN Give_Error "Invalid array bounds": EXIT SUB

            dim_tokens = numelements(dim_expr)
            to_position = 0
            inner_depth = 0
            FOR dim_token_index = 1 TO dim_tokens
                token = getelement$(dim_expr, dim_token_index)
                IF token = "(" THEN inner_depth = inner_depth + 1
                IF token = ")" THEN inner_depth = inner_depth - 1
                IF inner_depth < 0 THEN Give_Error "Invalid array bounds": EXIT SUB
                IF inner_depth = 0 AND UCASE$(token) = "TO" THEN
                    IF to_position THEN Give_Error "Invalid array bounds": EXIT SUB
                    to_position = dim_token_index
                END IF
            NEXT
            IF inner_depth <> 0 THEN Give_Error "Invalid array bounds": EXIT SUB

            IF to_position THEN
                lower_expr = getelements$(dim_expr, 1, to_position - 1)
                upper_expr = getelements$(dim_expr, to_position + 1, dim_tokens)
                IF lower_expr = "" OR upper_expr = "" THEN Give_Error "Invalid array bounds": EXIT SUB
            ELSE
                IF LTRIM$(RTRIM$(dim_expr)) = "0" THEN
                    lower_expr = "0"
                ELSE
                    lower_expr = _TOSTR$(optionbase + 0)
                END IF
                upper_expr = dim_expr
            END IF

            constequation = 1
            lower_ordered = fixoperationorder$(lower_expr)
            IF Error_Happened THEN EXIT SUB
            lower_text = evaluatetotyp$(lower_ordered, 64&)
            IF Error_Happened THEN EXIT SUB
            lower_is_const = constequation

            constequation = 1
            upper_ordered = fixoperationorder$(upper_expr)
            IF Error_Happened THEN EXIT SUB
            upper_text = evaluatetotyp$(upper_ordered, 64&)
            IF Error_Happened THEN EXIT SUB
            upper_is_const = constequation

            'Match allocarray(): reject impossible constant bounds in the IDE,
            'while retaining the generated runtime guard for variable expressions.
            IF upper_is_const THEN
                IF to_position THEN
                    IF lower_is_const THEN
                        IF VAL(upper_text) < VAL(lower_text) THEN Give_Error "Invalid array bounds": EXIT SUB
                    END IF
                ELSE
                    IF VAL(upper_text) < 0 THEN Give_Error "Invalid array bounds": EXIT SUB
                END IF
            END IF

            current_dim = current_dim + 1
            desc_index = (total_dims - current_dim) * 4 + 4
            lower_name = prep_prefix + "_d" + LTRIM$(STR$(current_dim)) + "_lo"
            upper_name = prep_prefix + "_d" + LTRIM$(STR$(current_dim)) + "_hi"
            lower64_name = lower_name + "64"
            upper64_name = upper_name + "64"

            acc = acc + cr + "static int64 " + lower64_name + ";"
            acc = acc + cr + "static int64 " + upper64_name + ";"
            acc = acc + cr + "static ptrszint " + lower_name + ";"
            acc = acc + cr + "static ptrszint " + upper_name + ";"
            acc = acc + cr + lower64_name + "=(int64)(" + lower_text + ");"
            acc = acc + cr + upper64_name + "=(int64)(" + upper_text + ");"
            acc = acc + cr + "if (((int64)((ptrszint)" + lower64_name + "))!=" + lower64_name + ") error(257);"
            acc = acc + cr + "if (((int64)((ptrszint)" + upper64_name + "))!=" + upper64_name + ") error(257);"
            acc = acc + cr + lower_name + "=(ptrszint)" + lower64_name + ";"
            acc = acc + cr + upper_name + "=(ptrszint)" + upper64_name + ";"
            acc = acc + cr + prep_prefix + "_lower=" + lower_name + ";"
            acc = acc + cr + prep_prefix + "_upper=" + upper_name + ";"
            acc = acc + cr + "if (" + prep_prefix + "_upper<" + prep_prefix + "_lower) error(5);"
            acc = acc + cr + desc_name + "[" + LTRIM$(STR$(desc_index)) + "]=" + prep_prefix + "_lower;"
            acc = acc + cr + desc_name + "[" + LTRIM$(STR$(desc_index + 1)) + "]=" + prep_prefix + "_upper-" + prep_prefix + "_lower+1;"
            acc = acc + cr + "if (" + desc_name + "[" + LTRIM$(STR$(desc_index + 1)) + "]<=0) error(5);"
            acc = acc + cr + desc_name + "[" + LTRIM$(STR$(desc_index + 2)) + "]=" + prep_prefix + "_stride;"
            acc = acc + cr + desc_name + "[" + LTRIM$(STR$(desc_index + 3)) + "]=0;"
            acc = acc + cr + prep_prefix + "_stride*=" + desc_name + "[" + LTRIM$(STR$(desc_index + 1)) + "];"

            first_index = token_index + 1
        END IF
    NEXT
END SUB

SUB AppendDynMemberLockBump (slotptr$, acc$)
    'Invalidate existing _MEM blocks before ERASE clears a descriptor-backed TYPE member array.
    'The descriptor remains owned by the scalar/parent UDT instance; only the lock id changes.
    DIM crlf$

    crlf$ = CHR$(13) + CHR$(10)
    acc$ = acc$ + "{" + crlf$
    acc$ = acc$ + "ptrszint *dyn_erase_desc=*((ptrszint**)(" + slotptr$ + "));" + crlf$
    acc$ = acc$ + "if (dyn_erase_desc&&dyn_erase_desc[3]>0){" + crlf$
    acc$ = acc$ + "ptrszint dyn_erase_lock_index=dyn_erase_desc[3]*4+4;" + crlf$
    acc$ = acc$ + "if (dyn_erase_desc[dyn_erase_lock_index]) ((mem_lock*)dyn_erase_desc[dyn_erase_lock_index])->id=(++mem_lock_id);" + crlf$
    acc$ = acc$ + "}" + crlf$
    acc$ = acc$ + "}" + crlf$
END SUB

FUNCTION UDTArrayIndexExpr$ (indexes$, dimension_count AS LONG, descriptor$)
    DIM result_expr AS STRING

    n = numelements(indexes$)
    IF n = 0 THEN Give_Error "Array index missing": EXIT FUNCTION
    IF dimension_count <= 0 THEN Give_Error "TYPE member is not an array": EXIT FUNCTION

    result_expr = ""
    stride = 1
    desc_pos = 1
    found_dimensions = 0
    b = 0
    firsti = 1

    FOR i = 1 TO n
        e$ = getelement$(indexes$, i)
        IF e$ = "(" THEN b = b + 1
        IF e$ = ")" THEN b = b - 1
        IF (b = 0 AND e$ = ",") OR i = n THEN
            IF i = n THEN
                idx_src$ = getelements$(indexes$, firsti, i)
            ELSE
                idx_src$ = getelements$(indexes$, firsti, i - 1)
            END IF
            idx_src$ = evaluatetotyp$(idx_src$, 64&)
            IF Error_Happened THEN EXIT FUNCTION
            IF idx_src$ = "" THEN Give_Error "Array index missing": EXIT FUNCTION

            found_dimensions = found_dimensions + 1
            IF found_dimensions > dimension_count THEN Give_Error "Cannot change the number of elements an array has!": EXIT FUNCTION
            IF ParseNextUDTArrayDescriptorDim(descriptor$, desc_pos, dim_lower, dim_elements) = 0 THEN Give_Error "Cannot process the declared bounds of this TYPE member array": EXIT FUNCTION

            dim_lower_txt$ = LTRIM$(STR$(dim_lower))
            dim_elements_txt$ = LTRIM$(STR$(dim_elements))
            stride_txt$ = LTRIM$(STR$(stride))

            IF found_dimensions = 1 THEN
                IF CheckingOn THEN
                    result_expr = result_expr + "array_check((" + idx_src$ + ")-(" + dim_lower_txt$ + ")," + dim_elements_txt$ + ")+"
                ELSE
                    result_expr = result_expr + "((" + idx_src$ + ")-(" + dim_lower_txt$ + "))+"
                END IF
            ELSE
                IF CheckingOn THEN
                    result_expr = result_expr + "array_check((" + idx_src$ + ")-(" + dim_lower_txt$ + ")," + dim_elements_txt$ + ")*" + stride_txt$ + "+"
                ELSE
                    result_expr = result_expr + "((" + idx_src$ + ")-(" + dim_lower_txt$ + "))*" + stride_txt$ + "+"
                END IF
            END IF

            stride = stride * dim_elements
            firsti = i + 1
        END IF
    NEXT

    IF found_dimensions <> dimension_count THEN Give_Error "Cannot change the number of elements an array has!": EXIT FUNCTION
    IF ParseNextUDTArrayDescriptorDim(descriptor$, desc_pos, dim_lower, dim_elements) THEN Give_Error "Cannot change the number of elements an array has!": EXIT FUNCTION
    IF result_expr = "" THEN Give_Error "Array index missing": EXIT FUNCTION

    UDTArrayIndexExpr$ = LEFT$(result_expr, LEN(result_expr) - 1)
END FUNCTION



FUNCTION DynMemberIndexDims% (indexes AS STRING)
    DIM token AS STRING
    DIM ntokens AS LONG
    DIM bracket_depth AS LONG
    DIM token_index AS LONG
    DIM actual_dimensions AS LONG

    ntokens = numelements(indexes)
    IF ntokens = 0 THEN EXIT FUNCTION

    actual_dimensions = 1
    bracket_depth = 0
    FOR token_index = 1 TO ntokens
        token = getelement$(indexes, token_index)
        IF token = "(" THEN bracket_depth = bracket_depth + 1
        IF token = ")" THEN bracket_depth = bracket_depth - 1
        IF bracket_depth < 0 THEN EXIT FUNCTION
        IF bracket_depth = 0 AND token = "," THEN actual_dimensions = actual_dimensions + 1
    NEXT
    IF bracket_depth <> 0 THEN EXIT FUNCTION

    DynMemberIndexDims% = actual_dimensions
END FUNCTION

FUNCTION UDTRootDataGuard$ (desc_expr AS STRING, udt_index AS LONG, layout_mode AS LONG)
    'Return a guarded data pointer for top-level UDT arrays, but only for
    'nested TYPE member-array accesses. error(9) alone is not enough here:
    'after ERASE the generated C expression still continues and would
    'dereference ARRAY_UDT_x[0] == nothingvalue. The dummy UDT element keeps
    'that expression safe while the pending runtime error is handled.
    DIM helper_name AS STRING
    DIM byte_count AS LONG
    DIM byte_count_text AS STRING
    DIM dummy_expr AS STRING

    IF udt_index <= 0 THEN Give_Error "Invalid user defined type": EXIT FUNCTION

    IF layout_mode <> 0 THEN
        byte_count = UDTDynLayoutSize&(udt_index) \ 8
    ELSE
        byte_count = udtxsize(udt_index) \ 8
    END IF
    IF byte_count <= 0 THEN byte_count = 1

    helper_name = "udt_root_data_guard_" + _TOSTR$(uniquenumber)
    byte_count_text = LTRIM$(STR$(byte_count))
    dummy_expr = "(void*)qb_dummy"

    WriteBufLine GlobTxtBuf, "static ptrszint " + helper_name + "(ptrszint *qb_arr){"
    WriteBufLine GlobTxtBuf, "static uint8 qb_dummy[" + byte_count_text + "];"
    WriteBufLine GlobTxtBuf, "static int qb_ready=0;"
    WriteBufLine GlobTxtBuf, "if (!qb_ready){"
    WriteBufLine GlobTxtBuf, "memset(qb_dummy,0," + byte_count_text + ");"
    IF layout_mode = 0 THEN
        initialise_udt_varstrings dummy_expr, udt_index, GlobTxtBuf, 0
    END IF
    WriteBufLine GlobTxtBuf, "qb_ready=1;"
    WriteBufLine GlobTxtBuf, "}"
    WriteBufLine GlobTxtBuf, "if ((!qb_arr)||(!(qb_arr[2]&1))||(!qb_arr[0])||(qb_arr[0]==(ptrszint)nothingvalue)){error(9); return (ptrszint)qb_dummy;}"
    WriteBufLine GlobTxtBuf, "return qb_arr[0];"
    WriteBufLine GlobTxtBuf, "}"

    UDTRootDataGuard$ = helper_name + "(" + desc_expr + ")"
END FUNCTION

'Return a guarded descriptor expression for descriptor-backed TYPE member arrays.
'If a member was erased or the parent expression is already in error, the generated
'C helper raises error(9) and returns a valid dummy descriptor/data area so later
'address arithmetic can finish without dereferencing NULL/nothingvalue.
FUNCTION UDTDynArrayDescGuard$ (desc_expr AS STRING, dimension_count AS LONG)
    DIM helper_name AS STRING
    DIM desc_slots AS LONG
    DIM dim_index AS LONG
    DIM desc_index AS LONG

    IF dimension_count <= 0 THEN Give_Error "TYPE member is not an array": EXIT FUNCTION

    helper_name = "udt_dyn_desc_" + _TOSTR$(uniquenumber)
    desc_slots = 4 * dimension_count + 4 + 1

    WriteBufLine GlobTxtBuf, "static ptrszint *" + helper_name + "(ptrszint *qb_desc){"
    WriteBufLine GlobTxtBuf, "static ptrszint qb_dummy[" + LTRIM$(STR$(desc_slots)) + "];"
    WriteBufLine GlobTxtBuf, "static uint8 qb_dummy_data[4096];"
    WriteBufLine GlobTxtBuf, "static qbs *qb_dummy_qbs=0;"
    WriteBufLine GlobTxtBuf, "int qb_dummy_i;"
    WriteBufLine GlobTxtBuf, "if (!qb_dummy[0]){"
    WriteBufLine GlobTxtBuf, "memset(qb_dummy_data,0,4096);"
    WriteBufLine GlobTxtBuf, "qb_dummy_qbs=qbs_new(0,0);"
    WriteBufLine GlobTxtBuf, "qb_dummy[0]=(ptrszint)qb_dummy_data;"
    WriteBufLine GlobTxtBuf, "qb_dummy[3]=" + LTRIM$(STR$(dimension_count)) + ";"
    FOR dim_index = 1 TO dimension_count
        desc_index = (dimension_count - dim_index) * 4 + 4
        WriteBufLine GlobTxtBuf, "qb_dummy[" + LTRIM$(STR$(desc_index)) + "]=0;"
        WriteBufLine GlobTxtBuf, "qb_dummy[" + LTRIM$(STR$(desc_index + 1)) + "]=1;"
        WriteBufLine GlobTxtBuf, "qb_dummy[" + LTRIM$(STR$(desc_index + 2)) + "]=1;"
        WriteBufLine GlobTxtBuf, "qb_dummy[" + LTRIM$(STR$(desc_index + 3)) + "]=0;"
    NEXT
    WriteBufLine GlobTxtBuf, "}"
    WriteBufLine GlobTxtBuf, "if ((!qb_desc)||(qb_desc[3]!=" + LTRIM$(STR$(dimension_count)) + ")){"
    WriteBufLine GlobTxtBuf, "error(9);"
    WriteBufLine GlobTxtBuf, "if (!qb_dummy_qbs) qb_dummy_qbs=qbs_new(0,0);"
    WriteBufLine GlobTxtBuf, "for(qb_dummy_i=0;qb_dummy_i+((int)sizeof(ptrszint))<=4096;qb_dummy_i+=((int)sizeof(ptrszint))) *((ptrszint*)(qb_dummy_data+qb_dummy_i))=(ptrszint)qb_dummy_qbs;"
    WriteBufLine GlobTxtBuf, "return qb_dummy;"
    WriteBufLine GlobTxtBuf, "}"
    WriteBufLine GlobTxtBuf, "return qb_desc;"
    WriteBufLine GlobTxtBuf, "}"

    UDTDynArrayDescGuard$ = helper_name + "(" + desc_expr + ")"
END FUNCTION

'Build the element-offset expression for an indexed descriptor-backed member array.
'The descriptor carries live lower/count/stride values, so this path mirrors normal
'QB64 dynamic-array indexing instead of using compile-time udtearraydesc metadata.
FUNCTION UDTDynArrayIndexExpr$ (indexes AS STRING, dimension_count AS LONG, desc_expr AS STRING)
    DIM result_expr AS STRING
    DIM idx_src AS STRING
    DIM dim_base AS STRING
    DIM dim_count AS STRING
    DIM dim_stride AS STRING
    DIM token AS STRING
    DIM ntokens AS LONG
    DIM found_dimensions AS LONG
    DIM actual_dimensions AS LONG
    DIM bracket_depth AS LONG
    DIM first_index AS LONG
    DIM token_index AS LONG
    DIM desc_index AS LONG

    ntokens = numelements(indexes)
    IF ntokens = 0 THEN Give_Error "Array index missing": EXIT FUNCTION

    actual_dimensions = dimension_count
    IF actual_dimensions <= 0 THEN
        actual_dimensions = 1
        bracket_depth = 0
        FOR token_index = 1 TO ntokens
            token = getelement$(indexes, token_index)
            IF token = "(" THEN bracket_depth = bracket_depth + 1
            IF token = ")" THEN bracket_depth = bracket_depth - 1
            IF bracket_depth = 0 AND token = "," THEN actual_dimensions = actual_dimensions + 1
        NEXT
    END IF
    IF actual_dimensions <= 0 THEN Give_Error "TYPE member is not an array": EXIT FUNCTION

    result_expr = ""
    found_dimensions = 0
    bracket_depth = 0
    first_index = 1

    FOR token_index = 1 TO ntokens
        token = getelement$(indexes, token_index)
        IF token = "(" THEN bracket_depth = bracket_depth + 1
        IF token = ")" THEN bracket_depth = bracket_depth - 1
        IF (bracket_depth = 0 AND token = ",") OR token_index = ntokens THEN
            IF token_index = ntokens THEN
                idx_src = getelements$(indexes, first_index, token_index)
            ELSE
                idx_src = getelements$(indexes, first_index, token_index - 1)
            END IF
            idx_src = evaluatetotyp$(idx_src, 64&)
            IF Error_Happened THEN EXIT FUNCTION
            IF idx_src = "" THEN Give_Error "Array index missing": EXIT FUNCTION

            found_dimensions = found_dimensions + 1
            IF found_dimensions > actual_dimensions THEN Give_Error "Cannot change the number of elements an array has!": EXIT FUNCTION

            desc_index = (actual_dimensions - found_dimensions) * 4 + 4
            dim_base = desc_expr + "[" + LTRIM$(STR$(desc_index)) + "]"
            dim_count = desc_expr + "[" + LTRIM$(STR$(desc_index + 1)) + "]"
            dim_stride = desc_expr + "[" + LTRIM$(STR$(desc_index + 2)) + "]"

            IF found_dimensions = 1 THEN
                IF CheckingOn THEN
                    result_expr = result_expr + "array_check((" + idx_src + ")-(" + dim_base + ")," + dim_count + ")+"
                ELSE
                    result_expr = result_expr + "((" + idx_src + ")-(" + dim_base + "))+"
                END IF
            ELSE
                IF CheckingOn THEN
                    result_expr = result_expr + "array_check((" + idx_src + ")-(" + dim_base + ")," + dim_count + ")*(" + dim_stride + ")+"
                ELSE
                    result_expr = result_expr + "((" + idx_src + ")-(" + dim_base + "))*(" + dim_stride + ")+"
                END IF
            END IF

            first_index = token_index + 1
        END IF
    NEXT

    IF found_dimensions <> actual_dimensions THEN Give_Error "Cannot change the number of elements an array has!": EXIT FUNCTION
    IF result_expr = "" THEN Give_Error "Array index missing": EXIT FUNCTION

    result_expr = "array_check(" + LTRIM$(STR$(actual_dimensions)) + "-(" + desc_expr + "[3]),1)+(" + LEFT$(result_expr, LEN(result_expr) - 1) + ")"

    UDTDynArrayIndexExpr$ = result_expr
END FUNCTION

FUNCTION CompactMemberRefLayout$ (src AS STRING)
    ' Rebuild a TYPE member reference into compact, stable source text for layout output.
    ' This preserves member-array declarators and dotted member chains without introducing unwanted spaces.

    DIM compacttxt AS STRING '
    DIM tok AS STRING
    DIM prevtok AS STRING
    DIM needspace AS LONG
    DIM ntok AS LONG
    DIM idx AS LONG

    compacttxt = ""
    prevtok = ""
    needspace = 0
    ntok = numelements(src)

    FOR idx = 1 TO ntok
        tok = getelement$(src, idx)
        IF tok = "," THEN
            compacttxt = RTRIM$(compacttxt) + ", "
            needspace = 0
        ELSEIF tok = "." THEN
            compacttxt = RTRIM$(compacttxt) + "."
            needspace = 0
        ELSEIF tok = "(" THEN
            compacttxt = RTRIM$(compacttxt) + "("
            needspace = 0
        ELSEIF tok = ")" THEN
            compacttxt = RTRIM$(compacttxt) + ")"
            needspace = 1

        ELSE 'update (previous version add space before minus if negative arrays bounds in valid range is declared)
            IF LEN(compacttxt) = 0 THEN
                compacttxt = tok
            ELSEIF needspace THEN
                compacttxt = compacttxt + sp + tok
            ELSEIF prevtok = "." OR prevtok = "(" THEN
                compacttxt = compacttxt + tok
            ELSE
                compacttxt = compacttxt + tok
            END IF

            needspace = 1

            'Unary + or - must remain attached to its operand.
            IF tok = "-" OR tok = "+" THEN
                IF prevtok = "" OR prevtok = "(" OR prevtok = "," OR UCASE$(prevtok) = "TO" THEN
                    needspace = 0
                END IF
            END IF
        END IF

        prevtok = tok
    NEXT

    CompactMemberRefLayout$ = compacttxt
END FUNCTION

FUNCTION UDTArrayBoundExpr$ (descriptor$, dimension_count AS LONG, dimension_expr$, want_upper AS LONG)
    DIM helper_name AS STRING
    DIM desc_pos AS LONG
    DIM dim_i AS LONG
    DIM dim_lower AS LONG
    DIM dim_elements AS LONG
    DIM bound_value AS LONG

    ' This helper is only used for inline TYPE member arrays (unmarked or _Static).
    ' These members do not have a normal QB64 array descriptor at runtime, so LBOUND/UBOUND
    ' cannot call func_lbound/func_ubound directly.
    '
    ' IMPORTANT:
    ' Do not generate inline expressions like (error(9),0) here. They can behave
    ' differently across compilers/platforms and break ON ERROR handling in CI.
    ' Instead emit a small normal C helper function and call it.
    IF dimension_count <= 0 THEN Give_Error "TYPE member is not an array": EXIT FUNCTION

    helper_name = "udt_array_bound_" + _TOSTR$(uniquenumber)

    WriteBufLine GlobTxtBuf, "static int64 " + helper_name + "(int64 qb_dim){"
    WriteBufLine GlobTxtBuf, "switch(qb_dim){"

    desc_pos = 1
    FOR dim_i = 1 TO dimension_count
        IF ParseNextUDTArrayDescriptorDim(descriptor$, desc_pos, dim_lower, dim_elements) = 0 THEN
            Give_Error "Cannot process the declared bounds of this TYPE member array": EXIT FUNCTION
        END IF

        IF want_upper THEN
            bound_value = dim_lower + dim_elements - 1
        ELSE
            bound_value = dim_lower
        END IF

        WriteBufLine GlobTxtBuf, "case " + _TOSTR$(dim_i) + ": return " + _TOSTR$(bound_value) + ";"
    NEXT

    WriteBufLine GlobTxtBuf, "default: error(9); return 0;"
    WriteBufLine GlobTxtBuf, "}"
    WriteBufLine GlobTxtBuf, "}"

    UDTArrayBoundExpr$ = helper_name + "(" + dimension_expr$ + ")"
END FUNCTION




'Emit a small C helper that computes the byte length of a descriptor-backed TYPE
'member array from its live descriptor. It performs count and multiplication checks
'before _MEM/LEN-style callers expose the raw payload size.
FUNCTION UDTDynArrayBytesExpr$ (desc_expr AS STRING, elem_bytes AS LONG)
    DIM helper_name AS STRING
    DIM elem_text AS STRING

    IF elem_bytes <= 0 THEN Give_Error "Cannot process the declared bounds of this TYPE member array": EXIT FUNCTION

    helper_name = "udt_dyn_array_bytes_" + _TOSTR$(uniquenumber)
    elem_text = LTRIM$(STR$(elem_bytes))

    WriteBufLine GlobTxtBuf, "static ptrszint " + helper_name + "(ptrszint *qb_desc){"
    WriteBufLine GlobTxtBuf, "ptrszint qb_i;"
    WriteBufLine GlobTxtBuf, "ptrszint qb_arg;"
    WriteBufLine GlobTxtBuf, "ptrszint qb_count;"
    WriteBufLine GlobTxtBuf, "uint64 qb_total=1;"
    WriteBufLine GlobTxtBuf, "if ((!qb_desc)||(qb_desc[3]<=0)){error(9); return 0;}"
    WriteBufLine GlobTxtBuf, "for(qb_i=1; qb_i<=qb_desc[3]; qb_i++){"
    WriteBufLine GlobTxtBuf, "qb_arg=(qb_desc[3]-qb_i)*4+4;"
    WriteBufLine GlobTxtBuf, "qb_count=qb_desc[qb_arg+1];"
    WriteBufLine GlobTxtBuf, "if (qb_count<0){error(9); return 0;}"
    WriteBufLine GlobTxtBuf, "if (qb_count&&qb_total>(18446744073709551615ull/(uint64)qb_count)){error(257); return 0;}"
    WriteBufLine GlobTxtBuf, "qb_total*=(uint64)qb_count;"
    WriteBufLine GlobTxtBuf, "}"
    WriteBufLine GlobTxtBuf, "if (qb_total>(18446744073709551615ull/(uint64)" + elem_text + ")){error(257); return 0;}"
    WriteBufLine GlobTxtBuf, "return (ptrszint)(qb_total*(uint64)" + elem_text + ");"
    WriteBufLine GlobTxtBuf, "}"

    UDTDynArrayBytesExpr$ = helper_name + "(" + desc_expr + ")"
END FUNCTION

FUNCTION UDTDynArrayBoundExpr$ (desc_expr AS STRING, dimension_expr AS STRING, want_upper AS LONG)
    DIM helper_name AS STRING

    ' Runtime descriptor-bound helper for explicit _Dynamic TYPE member arrays.
    ' The member descriptor stores the active dimension count in slot [3].
    ' Bounds for dimension N use the same descriptor layout as normal QB64 arrays:
    '   index = (dimension_count - N) * 4 + 4
    '   desc[index]     = lower bound
    '   desc[index + 1] = element count
    helper_name = "udt_dyn_array_bound_" + _TOSTR$(uniquenumber)

    WriteBufLine GlobTxtBuf, "static int64 " + helper_name + "(ptrszint *qb_desc,int64 qb_dim){"
    WriteBufLine GlobTxtBuf, "ptrszint qb_i;"
    WriteBufLine GlobTxtBuf, "if ((!qb_desc)||(qb_dim<1)||(qb_dim>qb_desc[3])){error(9); return 0;}"
    WriteBufLine GlobTxtBuf, "qb_i=(qb_desc[3]-qb_dim)*4+4;"
    IF want_upper THEN
        WriteBufLine GlobTxtBuf, "return qb_desc[qb_i]+qb_desc[qb_i+1]-1;"
    ELSE
        WriteBufLine GlobTxtBuf, "return qb_desc[qb_i];"
    END IF
    WriteBufLine GlobTxtBuf, "}"

    UDTDynArrayBoundExpr$ = helper_name + "(" + desc_expr + "," + dimension_expr + ")"
END FUNCTION

FUNCTION WholeArrayName$ (expr AS STRING)
    DIM elem_total AS LONG
    DIM candidate AS STRING

    elem_total = numelements(expr)
    IF elem_total <> 3 THEN EXIT FUNCTION
    IF getelement$(expr, 2) <> "(" THEN EXIT FUNCTION
    IF getelement$(expr, 3) <> ")" THEN EXIT FUNCTION

    candidate = getelement$(expr, 1)
    IF validname(candidate) = 0 THEN EXIT FUNCTION
    WholeArrayName$ = candidate
END FUNCTION

'Emit whole-array assignment for descriptor-layout UDT arrays, e.g. dst() = src().
'This validates both arrays and requires identical bounds, then performs deep-copy
'semantics so destination descriptors/qbs strings are independent from the source.
SUB AppendDynUDTArrayAssign (dstarr AS STRING, srcarr AS STRING, udt AS LONG, layout_mode AS LONG, arrdims AS LONG)
    DIM elembytes AS STRING
    DIM owncopy AS STRING
    DIM freecopy AS STRING
    DIM inpcopy AS STRING

    elembytes = _TOSTR$(UDTDynLayoutSize&(udt) \ 8)

    WriteBufLine MainTxtBuf, "{"
    WriteBufLine MainTxtBuf, "ptrszint *dyn_arr_dst=" + dstarr + ";"
    WriteBufLine MainTxtBuf, "ptrszint *dyn_arr_src=" + srcarr + ";"
    WriteBufLine MainTxtBuf, "if ((!dyn_arr_dst[0])||(!dyn_arr_src[0])||(dyn_arr_dst[0]==(ptrszint)nothingvalue)||(dyn_arr_src[0]==(ptrszint)nothingvalue)) error(9);"
    WriteBufLine MainTxtBuf, "uint64 dyn_arr_total=1;"
    WriteBufLine MainTxtBuf, "for(ptrszint dyn_arr_i=1; dyn_arr_i<=" + _TOSTR$(arrdims) + "; dyn_arr_i++){"
    WriteBufLine MainTxtBuf, "ptrszint dyn_arr_arg=(" + _TOSTR$(arrdims) + "-dyn_arr_i)*4+4;"
    WriteBufLine MainTxtBuf, "if ((dyn_arr_dst[dyn_arr_arg]!=dyn_arr_src[dyn_arr_arg])||(dyn_arr_dst[dyn_arr_arg+1]!=dyn_arr_src[dyn_arr_arg+1])) error(9);"
    WriteBufLine MainTxtBuf, "if (dyn_arr_dst[dyn_arr_arg+1]<0) error(9);"
    WriteBufLine MainTxtBuf, "if (dyn_arr_dst[dyn_arr_arg+1]&&dyn_arr_total>(18446744073709551615ull/(uint64)dyn_arr_dst[dyn_arr_arg+1])) error(9);"
    WriteBufLine MainTxtBuf, "dyn_arr_total*=(uint64)dyn_arr_dst[dyn_arr_arg+1];"
    WriteBufLine MainTxtBuf, "}"
    WriteBufLine MainTxtBuf, "if (dyn_arr_dst[0]!=dyn_arr_src[0]){"

    IF udtxvariable(udt) THEN
        ' Owner-layout whole-array assignment has two safe paths:
        '
        ' * REDIM/heap-backed parent arrays can use replace-copy: build a complete fresh payload,
        '   deep-clone the source into it, free the old destination payload, then swap
        '   the parent array data pointer.
        '
        ' * DIM/static-storage parent arrays cannot use replace-copy. Their data pointer refers to
        '   static storage owned by the array descriptor, so freeing or replacing it is
        '   invalid.  For those arrays, assign element-by-element in-place using the
        '   ownership-aware setter.  This still erases/replaces each destination
        '   element's owned qbs/descriptors, but it never frees the parent storage.
        owncopy = ""
        freecopy = ""
        inpcopy = ""
        WriteBufLine MainTxtBuf, "if (dyn_arr_dst[2]&2){"
        WriteBufLine MainTxtBuf, "for(ptrszint dyn_arr_i=0; dyn_arr_i<(ptrszint)dyn_arr_total; dyn_arr_i++){"
        AppendDynUDTOwnSetAt "(void*)dyn_arr_dst[0]", "(void*)dyn_arr_src[0]", udt, 0, 0, elembytes, "dyn_arr_i", "dyn_arr_i", inpcopy, layout_mode
        IF Error_Happened THEN EXIT SUB
        WriteBufLine MainTxtBuf, inpcopy
        WriteBufLine MainTxtBuf, "}"
        WriteBufLine MainTxtBuf, "}else{"
        WriteBufLine MainTxtBuf, "if (dyn_arr_total&&dyn_arr_total>(18446744073709551615ull/(uint64)" + elembytes + ")) error(257);"
        WriteBufLine MainTxtBuf, "uint64 dyn_arr_bytes=dyn_arr_total*(uint64)" + elembytes + ";"
        WriteBufLine MainTxtBuf, "uint8 *dyn_arr_new_data=NULL;"
        WriteBufLine MainTxtBuf, "if (dyn_arr_bytes){"
        WriteBufLine MainTxtBuf, "if (dyn_arr_dst[2]&4){"
        WriteBufLine MainTxtBuf, "dyn_arr_new_data=(uint8*)cmem_dynamic_malloc((size_t)dyn_arr_bytes);"
        WriteBufLine MainTxtBuf, "if (!dyn_arr_new_data) error(257);"
        WriteBufLine MainTxtBuf, "memset((void*)dyn_arr_new_data,0,(size_t)dyn_arr_bytes);"
        WriteBufLine MainTxtBuf, "}else{"
        WriteBufLine MainTxtBuf, "dyn_arr_new_data=(uint8*)calloc((size_t)dyn_arr_bytes,1);"
        WriteBufLine MainTxtBuf, "if (!dyn_arr_new_data) error(257);"
        WriteBufLine MainTxtBuf, "}"
        WriteBufLine MainTxtBuf, "for(ptrszint dyn_arr_i=0; dyn_arr_i<(ptrszint)dyn_arr_total; dyn_arr_i++){"
        ' The replacement payload is calloc/zero-filled. Do not pre-initialize the
        ' destination owner element here. Use AppendDynUDTOwnCloneAt, not SetAt:
        ' the replacement payload is zero-filled and every element is cloned into
        ' a clean slot. This avoids the unsafe init -> erase -> clone pattern for
        ' nested owner graphs by avoiding initialization followed immediately by erase.
        AppendDynUDTOwnCloneAt "(void*)dyn_arr_new_data", "(void*)dyn_arr_src[0]", udt, 0, 0, elembytes, "dyn_arr_i", "dyn_arr_i", owncopy, layout_mode
        IF Error_Happened THEN EXIT SUB
        WriteBufLine MainTxtBuf, owncopy
        WriteBufLine MainTxtBuf, "}"
        WriteBufLine MainTxtBuf, "}"
        WriteBufLine MainTxtBuf, "if (dyn_arr_dst[0]&&dyn_arr_dst[0]!=(ptrszint)nothingvalue){"
        WriteBufLine MainTxtBuf, "for(ptrszint dyn_arr_i=0; dyn_arr_i<(ptrszint)dyn_arr_total; dyn_arr_i++){"
        AppendDynUDTOwnFreeAt "(void*)dyn_arr_dst[0]", udt, 0, elembytes, "dyn_arr_i", freecopy, layout_mode
        IF Error_Happened THEN EXIT SUB
        WriteBufLine MainTxtBuf, freecopy
        WriteBufLine MainTxtBuf, "}"
        WriteBufLine MainTxtBuf, "if (dyn_arr_dst[2]&4) cmem_dynamic_free((uint8*)dyn_arr_dst[0]); else free((void*)dyn_arr_dst[0]);"
        WriteBufLine MainTxtBuf, "}"
        WriteBufLine MainTxtBuf, "dyn_arr_dst[0]=(ptrszint)dyn_arr_new_data;"
        WriteBufLine MainTxtBuf, "((mem_lock*)((ptrszint*)dyn_arr_dst)[8])->id=(++mem_lock_id);"
        WriteBufLine MainTxtBuf, "}"
    ELSE
        WriteBufLine MainTxtBuf, "for(ptrszint dyn_arr_i=0; dyn_arr_i<(ptrszint)dyn_arr_total; dyn_arr_i++){"
        WriteBufLine MainTxtBuf, "uint8 *dyn_elem_dst=((uint8*)dyn_arr_dst[0])+dyn_arr_i*" + elembytes + ";"
        WriteBufLine MainTxtBuf, "uint8 *dyn_elem_src=((uint8*)dyn_arr_src[0])+dyn_arr_i*" + elembytes + ";"
        copy_full_udt_dyn "dyn_elem_dst", "dyn_elem_src", MainTxtBuf, 0, udt, layout_mode
        IF Error_Happened THEN EXIT SUB
        WriteBufLine MainTxtBuf, "}"
    END IF

    WriteBufLine MainTxtBuf, "}"
    WriteBufLine MainTxtBuf, "}"
END SUB


'Build the runtime array descriptor required when a whole array member of a TYPE
'is passed to an array parameter. Descriptor-backed _Dynamic members already own
'a normal QB64 array descriptor and can be passed directly. Inline member arrays
'(unmarked or _Static) need a temporary descriptor lasting through the called SUB/FUNCTION.
SUB BuildUDTMemberArg (ref_text AS STRING, arg_text AS STRING, prep_text AS STRING, dim_count AS LONG)
    DIM AS STRING offset_text, root_text, array_desc_text, desc_text
    DIM AS STRING temp_name, crlf_text, data_text
    DIM AS LONG sep1, sep2, sep3, id_number, member_id
    DIM AS LONG parent_udt, parent_mode, slot_count, flag_value
    DIM AS LONG desc_pos, dim_index, dim_lower, dim_elements
    DIM AS LONG slot_index, stride_value, lock_index, nested_udt

    arg_text = ""
    prep_text = ""
    dim_count = 0

    sep1 = INSTR(ref_text, sp3)
    IF sep1 = 0 THEN Give_Error "Expected arrayname()": EXIT SUB
    sep2 = INSTR(sep1 + LEN(sp3), ref_text, sp3)
    IF sep2 = 0 THEN Give_Error "Expected arrayname()": EXIT SUB
    sep3 = INSTR(sep2 + LEN(sp3), ref_text, sp3)
    IF sep3 = 0 THEN Give_Error "Expected arrayname()": EXIT SUB

    id_number = VAL(LEFT$(ref_text, sep1 - 1))
    member_id = VAL(MID$(ref_text, sep2 + LEN(sp3), sep3 - sep2 - LEN(sp3)))
    IF member_id <= 0 THEN Give_Error "Expected arrayname()": EXIT SUB
    IF udtearrayelements(member_id) <= 0 THEN Give_Error "Expected arrayname()": EXIT SUB

    dim_count = udtearraydims(member_id)
    IF dim_count <= 0 THEN Give_Error "Expected arrayname()": EXIT SUB
    offset_text = MID$(ref_text, sep3 + LEN(sp3))

    getid id_number
    IF Error_Happened THEN EXIT SUB

    parent_mode = 0
    IF id.dynudt THEN parent_mode = id.dynudtmode

    root_text = scope$ + "UDT_" + RTRIM$(id.n)
    IF id.arraytype THEN
        array_desc_text = scope$ + "ARRAY_UDT_" + RTRIM$(id.n)
        root_text = array_desc_text + "[0]"
        parent_udt = id.arraytype AND UDTMASK
        IF CheckingOn THEN
            root_text = UDTRootDataGuard$(array_desc_text, parent_udt, parent_mode)
            IF Error_Happened THEN EXIT SUB
        END IF
    ELSE
        parent_udt = id.t AND UDTMASK
    END IF

    IF id.dynudt AND UDTMemberDynDesc%(member_id) THEN
        desc_text = "(*((ptrszint**)(((char*)" + root_text + ")+(" + offset_text + "))))"
        desc_text = UDTDynArrayDescGuard$(desc_text, dim_count)
        IF Error_Happened THEN EXIT SUB
        arg_text = desc_text
        EXIT SUB
    END IF

    temp_name = "udt_member_arg_" + _TOSTR$(uniquenumber)
    slot_count = 4 * dim_count + 5
    lock_index = 4 * dim_count + 4
    flag_value = 1 + 2
    IF (id.t AND ISINCONVENTIONALMEMORY) OR (id.arraytype AND ISINCONVENTIONALMEMORY) THEN flag_value = flag_value + 4

    IF udtetype(member_id) AND ISUDT THEN
        nested_udt = udtetype(member_id) AND UDTMASK
        IF parent_mode > 0 THEN
            IF UDTDynHasMemberArrays%(nested_udt, parent_mode) THEN flag_value = flag_value + 8
        END IF
    END IF

    crlf_text = CHR$(13) + CHR$(10)
    data_text = "(((char*)" + root_text + ")+(" + offset_text + "))"

    prep_text = "ptrszint " + temp_name + "[" + _TOSTR$(slot_count) + "];" + crlf_text
    prep_text = prep_text + temp_name + "[0]=(ptrszint)" + data_text + ";" + crlf_text
    prep_text = prep_text + temp_name + "[1]=0;" + crlf_text
    prep_text = prep_text + temp_name + "[2]=" + _TOSTR$(flag_value) + ";" + crlf_text
    prep_text = prep_text + temp_name + "[3]=" + _TOSTR$(dim_count) + ";" + crlf_text

    desc_pos = 1
    stride_value = 1
    FOR dim_index = 1 TO dim_count
        IF ParseNextUDTArrayDescriptorDim(udtearraydesc(member_id), desc_pos, dim_lower, dim_elements) = 0 THEN
            Give_Error "Cannot process the declared bounds of this TYPE member array": EXIT SUB
        END IF

        slot_index = (dim_count - dim_index) * 4 + 4
        prep_text = prep_text + temp_name + "[" + _TOSTR$(slot_index) + "]=" + _TOSTR$(dim_lower) + ";" + crlf_text
        prep_text = prep_text + temp_name + "[" + _TOSTR$(slot_index + 1) + "]=" + _TOSTR$(dim_elements) + ";" + crlf_text
        prep_text = prep_text + temp_name + "[" + _TOSTR$(slot_index + 2) + "]=" + _TOSTR$(stride_value) + ";" + crlf_text
        prep_text = prep_text + temp_name + "[" + _TOSTR$(slot_index + 3) + "]=0;" + crlf_text
        stride_value = stride_value * dim_elements
    NEXT

    prep_text = prep_text + temp_name + "[" + _TOSTR$(lock_index) + "]=(ptrszint)sf_mem_lock;" + crlf_text
    arg_text = temp_name
END SUB

SUB AppendUDTFileBoundsCheck (desc_expr AS STRING, member_id AS LONG, acc AS STRING)
    DIM cr AS STRING
    DIM desc_scan AS LONG
    DIM dim_index AS LONG
    DIM dim_count AS LONG
    DIM dim_lower AS LONG
    DIM elem_count AS LONG
    DIM slot_index AS LONG

    cr = CHR$(13) + CHR$(10)
    dim_count = udtearraydims(member_id)
    acc = acc + cr + "if ((!" + desc_expr + ")||(" + desc_expr + "[3]!=" + _TOSTR$(dim_count) + ")) error(9);"
    desc_scan = 1
    FOR dim_index = 1 TO dim_count
        IF ParseNextUDTArrayDescriptorDim(udtearraydesc(member_id), desc_scan, dim_lower, elem_count) = 0 THEN
            Give_Error "Cannot process the declared bounds of this TYPE member array"
            EXIT SUB
        END IF
        slot_index = (dim_count - dim_index) * 4 + 4
        acc = acc + cr + "if ((" + desc_expr + "[" + _TOSTR$(slot_index) + "]!=" + _TOSTR$(dim_lower) + ")||(" + desc_expr + "[" + _TOSTR$(slot_index + 1) + "]!=" + _TOSTR$(elem_count) + ")) error(9);"
    NEXT
    acc = acc + cr + "if ((!" + desc_expr + "[0])||(" + desc_expr + "[0]==(ptrszint)nothingvalue)) error(9);"
END SUB

'Emit pack/unpack C code between the declaration-time inline file layout and the
'physical descriptor layout. PUT writes the inline payload; GET unpacks that payload
'into live descriptor-backed member arrays after bounds
'compatibility has been checked.
SUB AppendUDTFileConvCode (dst_expr AS STRING, src_expr AS STRING, udt_index AS LONG, layout_mode AS LONG, do_unpack AS LONG, acc AS STRING)
    DIM elemnum AS LONG
    DIM nested_udt AS LONG
    DIM stat_bit AS LONG
    DIM dyn_bit AS LONG
    DIM stat_off AS LONG
    DIM dyn_off AS LONG
    DIM stat_bytes AS LONG
    DIM dyn_bytes AS LONG
    DIM elem_total AS LONG
    DIM stat_elem_bytes AS LONG
    DIM dyn_elem_bytes AS LONG
    DIM loop_name AS STRING
    DIM desc_name AS STRING
    DIM dst_member AS STRING
    DIM src_member AS STRING
    DIM dst_next AS STRING
    DIM src_next AS STRING
    DIM cr AS STRING

    cr = CHR$(13) + CHR$(10)
    elemnum = udtxnext(udt_index)
    stat_bit = 0
    dyn_bit = 0

    DO WHILE elemnum
        IF stat_bit MOD 8 THEN Give_Error "Non-byte aligned user defined type": EXIT SUB
        IF dyn_bit MOD 8 THEN Give_Error "Non-byte aligned user defined type": EXIT SUB

        stat_off = stat_bit \ 8
        dyn_off = dyn_bit \ 8
        stat_bytes = udtesize(elemnum) \ 8
        dyn_bytes = UDTDynMemberSize&(elemnum) \ 8
        nested_udt = 0
        IF (udtetype(elemnum) AND ISUDT) <> 0 THEN nested_udt = udtetype(elemnum) AND UDTMASK

        IF UDTMemberDynDesc%(elemnum) THEN
            desc_name = "file_dyn_desc_" + _TOSTR$(uniquenumber)
            IF do_unpack THEN
                acc = acc + cr + "ptrszint *" + desc_name + "=*((ptrszint**)(((uint8*)" + dst_expr + ")+" + _TOSTR$(dyn_off) + "));"
            ELSE
                acc = acc + cr + "ptrszint *" + desc_name + "=*((ptrszint**)(((uint8*)" + src_expr + ")+" + _TOSTR$(dyn_off) + "));"
            END IF
            AppendUDTFileBoundsCheck desc_name, elemnum, acc
            IF Error_Happened THEN EXIT SUB

            IF nested_udt <> 0 AND UDTDynHasMemberArrays%(nested_udt, layout_mode) THEN
                elem_total = udtearrayelements(elemnum)
                stat_elem_bytes = udtxsize(nested_udt) \ 8
                dyn_elem_bytes = udt_dyn_array_elem_bytes(elemnum)
                loop_name = "file_elem_i_" + _TOSTR$(uniquenumber)
                acc = acc + cr + "for(ptrszint " + loop_name + "=0; " + loop_name + "<" + _TOSTR$(elem_total) + "; " + loop_name + "++){"
                IF do_unpack THEN
                    dst_next = "((uint8*)" + desc_name + "[0]+" + loop_name + "*" + _TOSTR$(dyn_elem_bytes) + ")"
                    src_next = "((uint8*)" + src_expr + "+" + _TOSTR$(stat_off) + "+" + loop_name + "*" + _TOSTR$(stat_elem_bytes) + ")"
                ELSE
                    dst_next = "((uint8*)" + dst_expr + "+" + _TOSTR$(stat_off) + "+" + loop_name + "*" + _TOSTR$(stat_elem_bytes) + ")"
                    src_next = "((uint8*)" + desc_name + "[0]+" + loop_name + "*" + _TOSTR$(dyn_elem_bytes) + ")"
                END IF
                AppendUDTFileConvCode dst_next, src_next, nested_udt, layout_mode, do_unpack, acc
                IF Error_Happened THEN EXIT SUB
                acc = acc + cr + "}"
            ELSE
                IF do_unpack THEN
                    acc = acc + cr + "memcpy((void*)" + desc_name + "[0],(void*)(((uint8*)" + src_expr + ")+" + _TOSTR$(stat_off) + ")," + _TOSTR$(stat_bytes) + ");"
                ELSE
                    acc = acc + cr + "memcpy((void*)(((uint8*)" + dst_expr + ")+" + _TOSTR$(stat_off) + "),(void*)" + desc_name + "[0]," + _TOSTR$(stat_bytes) + ");"
                END IF
            END IF

        ELSEIF nested_udt <> 0 AND UDTDynHasMemberArrays%(nested_udt, layout_mode) THEN
            elem_total = 1
            IF udtearrayelements(elemnum) THEN elem_total = udtearrayelements(elemnum)
            stat_elem_bytes = udtxsize(nested_udt) \ 8
            dyn_elem_bytes = UDTDynMemberSize&(elemnum) \ 8
            IF udtearrayelements(elemnum) THEN dyn_elem_bytes = dyn_elem_bytes \ elem_total
            loop_name = "file_nest_i_" + _TOSTR$(uniquenumber)
            acc = acc + cr + "for(ptrszint " + loop_name + "=0; " + loop_name + "<" + _TOSTR$(elem_total) + "; " + loop_name + "++){"
            dst_next = "((uint8*)" + dst_expr + "+" + _TOSTR$(stat_off) + "+" + loop_name + "*" + _TOSTR$(stat_elem_bytes) + ")"
            src_next = "((uint8*)" + src_expr + "+" + _TOSTR$(dyn_off) + "+" + loop_name + "*" + _TOSTR$(dyn_elem_bytes) + ")"
            IF do_unpack THEN
                dst_next = "((uint8*)" + dst_expr + "+" + _TOSTR$(dyn_off) + "+" + loop_name + "*" + _TOSTR$(dyn_elem_bytes) + ")"
                src_next = "((uint8*)" + src_expr + "+" + _TOSTR$(stat_off) + "+" + loop_name + "*" + _TOSTR$(stat_elem_bytes) + ")"
            END IF
            AppendUDTFileConvCode dst_next, src_next, nested_udt, layout_mode, do_unpack, acc
            IF Error_Happened THEN EXIT SUB
            acc = acc + cr + "}"
        ELSE
            dst_member = "(((uint8*)" + dst_expr + ")+" + _TOSTR$(stat_off) + ")"
            src_member = "(((uint8*)" + src_expr + ")+" + _TOSTR$(dyn_off) + ")"
            IF do_unpack THEN
                dst_member = "(((uint8*)" + dst_expr + ")+" + _TOSTR$(dyn_off) + ")"
                src_member = "(((uint8*)" + src_expr + ")+" + _TOSTR$(stat_off) + ")"
            END IF
            acc = acc + cr + "memcpy((void*)" + dst_member + ",(void*)" + src_member + "," + _TOSTR$(stat_bytes) + ");"
        END IF

        stat_bit = stat_bit + udtesize(elemnum)
        dyn_bit = dyn_bit + UDTDynMemberSize&(elemnum)
        elemnum = udtenext(elemnum)
    LOOP
END SUB

'Return a byte_element view for PUT/GET on fixed-size descriptor-layout UDT arrays.
'The helper owns a temporary declaration-time inline-layout buffer: PUT packs descriptors into it,
'while GET reads into it first and post_call later commits the unpacked data back
'into the live UDT descriptors.
FUNCTION UDTFileArrayBE$ (arr_expr AS STRING, udt_index AS LONG, layout_mode AS LONG, dim_count AS LONG, do_get AS LONG, post_call AS STRING)
    DIM helper_name AS STRING
    DIM pack_name AS STRING
    DIM unpack_name AS STRING
    DIM buf_name AS STRING
    DIM size_name AS STRING
    DIM acc AS STRING
    DIM stat_bytes AS LONG
    DIM dyn_bytes AS LONG
    DIM be_name AS STRING

    IF udtxvariable(udt_index) THEN Give_Error "UDT must have fixed size": EXIT FUNCTION
    IF UDTDynHasMemberArrays%(udt_index, layout_mode) = 0 THEN Give_Error "PUT/GET cannot convert this TYPE value in the requested form": EXIT FUNCTION

    helper_name = "udt_file_array_" + _TOSTR$(uniquenumber)
    pack_name = helper_name + "_pack"
    unpack_name = helper_name + "_unpack"
    buf_name = helper_name + "_buf"
    size_name = helper_name + "_size"
    stat_bytes = udtxsize(udt_index) \ 8
    dyn_bytes = UDTDynLayoutSize&(udt_index) \ 8

    WriteBufLine GlobTxtBuf, "static uint8 *" + buf_name + "=NULL;"
    WriteBufLine GlobTxtBuf, "static uint64 " + size_name + "=0;"

    acc = ""
    AppendUDTFileConvCode "qb_dst", "qb_src", udt_index, layout_mode, 0, acc
    IF Error_Happened THEN EXIT FUNCTION
    WriteBufLine GlobTxtBuf, "static void " + pack_name + "(uint8 *qb_dst,uint8 *qb_src){"
    WriteBufLine GlobTxtBuf, acc
    WriteBufLine GlobTxtBuf, "}"

    acc = ""
    AppendUDTFileConvCode "qb_dst", "qb_src", udt_index, layout_mode, -1, acc
    IF Error_Happened THEN EXIT FUNCTION
    WriteBufLine GlobTxtBuf, "static void " + unpack_name + "(uint8 *qb_dst,uint8 *qb_src){"
    WriteBufLine GlobTxtBuf, acc
    WriteBufLine GlobTxtBuf, "}"

    WriteBufLine GlobTxtBuf, "static uint64 " + helper_name + "_total(ptrszint *qb_arr){"
    WriteBufLine GlobTxtBuf, "uint64 qb_total=1;"
    WriteBufLine GlobTxtBuf, "if ((!qb_arr)||(!(qb_arr[2]&1))) error(9);"
    FOR dim_i = 1 TO dim_count
        slot_index = dim_i * 4 - 4 + 5
        WriteBufLine GlobTxtBuf, "if (qb_arr[" + _TOSTR$(slot_index) + "]<0) error(9);"
        WriteBufLine GlobTxtBuf, "if (qb_arr[" + _TOSTR$(slot_index) + "]&&qb_total>(18446744073709551615ull/(uint64)qb_arr[" + _TOSTR$(slot_index) + "])) error(257);"
        WriteBufLine GlobTxtBuf, "qb_total*=(uint64)qb_arr[" + _TOSTR$(slot_index) + "];"
    NEXT
    WriteBufLine GlobTxtBuf, "return qb_total;"
    WriteBufLine GlobTxtBuf, "}"

    WriteBufLine GlobTxtBuf, "static byte_element_struct *" + helper_name + "_be(ptrszint *qb_arr,byte_element_struct *qb_be,int32 qb_pack){"
    WriteBufLine GlobTxtBuf, "uint64 qb_total=" + helper_name + "_total(qb_arr);"
    WriteBufLine GlobTxtBuf, "uint64 qb_need=qb_total*(uint64)" + _TOSTR$(stat_bytes) + ";"
    WriteBufLine GlobTxtBuf, "if (qb_total&&qb_need/(uint64)" + _TOSTR$(stat_bytes) + "!=qb_total) error(257);"
    WriteBufLine GlobTxtBuf, "if (" + size_name + "<qb_need){"
    WriteBufLine GlobTxtBuf, "uint8 *qb_new=(uint8*)realloc(" + buf_name + ",(size_t)qb_need);"
    WriteBufLine GlobTxtBuf, "if ((!qb_new)&&qb_need) error(257);"
    WriteBufLine GlobTxtBuf, buf_name + "=qb_new; " + size_name + "=qb_need;"
    WriteBufLine GlobTxtBuf, "}"
    WriteBufLine GlobTxtBuf, "if (qb_pack){for(ptrszint qb_i=0; qb_i<(ptrszint)qb_total; qb_i++){"
    WriteBufLine GlobTxtBuf, pack_name + "(" + buf_name + "+qb_i*" + _TOSTR$(stat_bytes) + ",((uint8*)qb_arr[0])+qb_i*" + _TOSTR$(dyn_bytes) + ");"
    WriteBufLine GlobTxtBuf, "}}"
    WriteBufLine GlobTxtBuf, "return (byte_element_struct*)byte_element((uint64)" + buf_name + ",(ptrszint)qb_need,qb_be);"
    WriteBufLine GlobTxtBuf, "}"

    IF do_get THEN
        WriteBufLine GlobTxtBuf, "static void " + helper_name + "_commit(ptrszint *qb_arr){"
        WriteBufLine GlobTxtBuf, "uint64 qb_total=" + helper_name + "_total(qb_arr);"
        WriteBufLine GlobTxtBuf, "uint64 qb_need=qb_total*(uint64)" + _TOSTR$(stat_bytes) + ";"
        WriteBufLine GlobTxtBuf, "if ((!" + buf_name + ")||(" + size_name + "<qb_need)) error(257);"
        WriteBufLine GlobTxtBuf, "for(ptrszint qb_i=0; qb_i<(ptrszint)qb_total; qb_i++){"
        WriteBufLine GlobTxtBuf, unpack_name + "(((uint8*)qb_arr[0])+qb_i*" + _TOSTR$(dyn_bytes) + "," + buf_name + "+qb_i*" + _TOSTR$(stat_bytes) + ");"
        WriteBufLine GlobTxtBuf, "}"
        WriteBufLine GlobTxtBuf, "}"
        post_call = helper_name + "_commit(" + arr_expr + ");"
    END IF

    be_name = NewByteElement$
    IF do_get THEN
        UDTFileArrayBE$ = helper_name + "_be(" + arr_expr + "," + be_name + ",0)"
    ELSE
        UDTFileArrayBE$ = helper_name + "_be(" + arr_expr + "," + be_name + ",1)"
    END IF
END FUNCTION


SUB assign (a$, n)
    DIM lhswhole AS STRING
    DIM rhswhole AS STRING
    DIM rhsall AS STRING
    DIM lhsid AS idstruct
    DIM rhsid AS idstruct
    DIM lhsok AS LONG
    DIM rhsok AS LONG
    DIM lhsudt AS LONG
    DIM rhsudt AS LONG

    FOR i = 1 TO n
        c = ASC(getelement$(a$, i))
        IF c = 40 THEN b = b + 1 '(
        IF c = 41 THEN b = b - 1 ')
        IF c = 61 AND b = 0 THEN '=
            IF i = 1 THEN Give_Error "Expected ... =": EXIT SUB
            IF i = n THEN Give_Error "Expected = ...": EXIT SUB

            a2$ = fixoperationorder(getelements$(a$, 1, i - 1))
            IF Error_Happened THEN EXIT SUB
            l$ = tlayout$ + sp + "=" + sp

            rhsall = getelements$(a$, i + 1, n)
            lhswhole = WholeArrayName$(a2$)
            rhswhole = WholeArrayName$(rhsall)
            IF lhswhole <> "" AND rhswhole <> "" THEN
                lhsok = 0
                rhsok = 0
                try = findid(lhswhole)
                IF Error_Happened THEN EXIT SUB
                DO WHILE try
                    IF id.arraytype AND ISUDT THEN
                        lhsid = id
                        lhsok = -1
                        EXIT DO
                    END IF
                    IF try = 2 THEN findanotherid = 1: try = findid(lhswhole) ELSE try = 0
                    IF Error_Happened THEN EXIT SUB
                LOOP
                try = findid(rhswhole)
                IF Error_Happened THEN EXIT SUB
                DO WHILE try
                    IF id.arraytype AND ISUDT THEN
                        rhsid = id
                        rhsok = -1
                        EXIT DO
                    END IF
                    IF try = 2 THEN findanotherid = 1: try = findid(rhswhole) ELSE try = 0
                    IF Error_Happened THEN EXIT SUB
                LOOP
                IF lhsok AND rhsok THEN
                    lhsudt = lhsid.arraytype AND UDTMASK
                    rhsudt = rhsid.arraytype AND UDTMASK
                    IF lhsudt = rhsudt AND lhsid.dynudt AND rhsid.dynudt THEN
                        IF lhsid.dynudtmode <> rhsid.dynudtmode THEN Give_Error "Cannot assign these TYPE values because their nested-array storage layouts are incompatible": EXIT SUB
                        IF lhsid.arrayelements <> rhsid.arrayelements THEN Give_Error "Cannot assign arrays with different dimensions": EXIT SUB
                        IF UDTDynHasMemberArrays%(lhsudt, lhsid.dynudtmode) THEN
                            AppendDynUDTArrayAssign RTRIM$(lhsid.callname), RTRIM$(rhsid.callname), lhsudt, lhsid.dynudtmode, lhsid.arrayelements
                            IF Error_Happened THEN EXIT SUB
                            tlayout$ = l$ + rhswhole + "()"
                            EXIT SUB
                        END IF
                    ELSEIF lhsudt = rhsudt AND (lhsid.dynudt OR rhsid.dynudt) THEN
                        Give_Error "Cannot assign these TYPE values because their nested-array storage layouts are incompatible": EXIT SUB
                    END IF
                END IF
            END IF

            'note: evaluating a2$ will fail if it is setting a function's return value without this check (as the function, not the return-variable) will be found by evaluate)
            IF i = 2 THEN 'lhs has only 1 element
                try = findid(a2$)
                IF Error_Happened THEN EXIT SUB
                DO WHILE try
                    IF id.t THEN
                        IF subfuncn = id.insubfuncn THEN 'avoid global before local
                            IF (id.t AND ISUDT) = 0 THEN
                                makeidrefer a2$, typ
                                GOTO assignsimplevariable
                            END IF
                        END IF
                    END IF
                    IF try = 2 THEN findanotherid = 1: try = findid(a2$) ELSE try = 0
                    IF Error_Happened THEN EXIT SUB
                LOOP
            END IF

            a2$ = evaluate$(a2$, typ): IF Error_Happened THEN EXIT SUB
            assignsimplevariable:
            IF (typ AND ISREFERENCE) = 0 THEN Give_Error "Expected variable =, look for conflict with a CONST name": EXIT SUB
            setrefer a2$, typ, getelements$(a$, i + 1, n), 0
            IF Error_Happened THEN EXIT SUB
            tlayout$ = l$ + tlayout$

            EXIT SUB

        END IF '=,b=0
    NEXT
    Give_Error "Expected =": EXIT SUB
END SUB

SUB clearid
    id = cleariddata
END SUB

SUB vWatchVariable (this$, action AS _BYTE)
    STATIC totalLocalVariables AS LONG, localVariablesList$
    STATIC totalMainModuleVariables AS LONG, mainModuleVariablesList$

    SELECT CASE action
        CASE -1 'reset
            totalLocalVariables = 0
            localVariablesList$ = ""
            totalMainModuleVariables = 0
            mainModuleVariablesList$ = ""
        CASE 0 'add
            IF INSTR(vWatchVariableExclusions$, "@" + this$ + "@") > 0 OR LEFT$(this$, 12) = "_SUB_VWATCH_" THEN
                EXIT SUB
            END IF

            vWatchNewVariable$ = this$
            IF subfunc = "" THEN
                totalMainModuleVariables = totalMainModuleVariables + 1
                mainModuleVariablesList$ = mainModuleVariablesList$ + "vwatch_global_vars[" + _TOSTR$(totalMainModuleVariables - 1) + "] = &" + this$ + ";" + CRLF
                manageVariableList id.cn, this$, totalMainModuleVariables - 1, 0
            ELSE
                totalLocalVariables = totalLocalVariables + 1
                localVariablesList$ = localVariablesList$ + "vwatch_local_vars[" + _TOSTR$(totalLocalVariables - 1) + "] = &" + this$ + ";" + CRLF
                manageVariableList id.cn, this$, totalLocalVariables - 1, 0
            END IF
        CASE 1 'dump to data[].txt & reset
            IF subfunc = "" THEN
                IF totalMainModuleVariables > 0 THEN
                    WriteBufLine DataTxtBuf, "void *vwatch_local_vars[0];"
                    WriteBufLine GlobTxtBuf, "void *vwatch_global_vars[" + STR$(totalMainModuleVariables) + "];"
                    WriteBufLine DataTxtBuf, mainModuleVariablesList$
                ELSE
                    WriteBufLine DataTxtBuf, "void *vwatch_local_vars[0];"
                    WriteBufLine GlobTxtBuf, "void *vwatch_global_vars[0];"
                END IF

                mainModuleVariablesList$ = ""
                totalMainModuleVariables = 0
            ELSE
                IF subfunc <> "SUB_VWATCH" THEN
                    IF totalLocalVariables > 0 THEN
                        WriteBufLine DataTxtBuf, "void *vwatch_local_vars[" + STR$(totalLocalVariables) + "];"
                        WriteBufLine DataTxtBuf, localVariablesList$
                    ELSE
                        WriteBufLine DataTxtBuf, "void *vwatch_local_vars[0];"
                    END IF
                ELSE
                    WriteBufLine DataTxtBuf, "void *vwatch_local_vars[0];"
                END IF

                localVariablesList$ = ""
                totalLocalVariables = 0
            END IF
    END SELECT
END SUB

SUB vWatchAddLabel (this AS LONG, lastLine AS _BYTE)
    STATIC prevLabel AS LONG, prevSkip AS LONG

    IF lastLine = 0 THEN
        WHILE this > LEN(vWatchUsedLabels)
            vWatchUsedLabels = vWatchUsedLabels + SPACE$(1000)
            vWatchUsedSkipLabels = vWatchUsedSkipLabels + SPACE$(1000)
        WEND

        IF firstLineNumberLabelvWatch = 0 THEN
            firstLineNumberLabelvWatch = this
        ELSE
            IF prevSkip <> prevLabel THEN
                ASC(vWatchUsedSkipLabels, prevLabel) = 1
                WriteBufLine MainTxtBuf, "VWATCH_SKIPLABEL_" + _TOSTR$(prevLabel) + ":;"
                prevSkip = prevLabel
            END IF
        END IF

        IF prevLabel <> this THEN
            ASC(vWatchUsedLabels, this) = 1
            WriteBufLine MainTxtBuf, "VWATCH_LABEL_" + _TOSTR$(this) + ":;"
            prevLabel = this
            lastLineNumberLabelvWatch = this
        END IF
    ELSE
        IF prevSkip <> prevLabel THEN
            ASC(vWatchUsedSkipLabels, prevLabel) = 1
            WriteBufLine MainTxtBuf, "VWATCH_SKIPLABEL_" + _TOSTR$(prevLabel) + ":;"
            prevSkip = prevLabel
        END IF
    END IF
END SUB

SUB closeMainVwatchSection
    FOR i = firstLineNumberLabelvWatch TO lastLineNumberLabelvWatch
        IF ASC(vWatchUsedLabels, i) = 1 THEN
            WriteBufLine VWatchMainDispatchBuf, "    case " + _TOSTR$(i) + ":"
            WriteBufLine VWatchMainDispatchBuf, "        goto VWATCH_LABEL_" + _TOSTR$(i) + ";"
            WriteBufLine VWatchMainDispatchBuf, "        break;"
        END IF
    NEXT
    FOR i = firstLineNumberLabelvWatch TO lastLineNumberLabelvWatch
        IF ASC(vWatchUsedSkipLabels, i) = 1 THEN
            WriteBufLine VWatchMainSkipBuf, "    case -" + _TOSTR$(i) + ":"
            WriteBufLine VWatchMainSkipBuf, "        goto VWATCH_SKIPLABEL_" + _TOSTR$(i) + ";"
            WriteBufLine VWatchMainSkipBuf, "        break;"
        END IF
    NEXT
END SUB

SUB closemain
    IF GetRCStateVar(vWatchOn) = 1 THEN vWatchAddLabel 0, -1
    xend
    WriteBufLine MainTxtBuf, "return;"
    IF GetRCStateVar(vWatchOn) = 1 THEN
        WriteBufLine MainTxtBuf, "VWATCH_SETNEXTLINE:;"
        WriteBufLine MainTxtBuf, "switch (*__LONG_VWATCH_GOTO) {"
        WriteBufLine MainTxtBuf, "#include " + CHR$(34) + "vw_main_dispatch.txt" + CHR$(34)
        WriteBufLine MainTxtBuf, "    default:"
        WriteBufLine MainTxtBuf, "        *__LONG_VWATCH_GOTO=*__LONG_VWATCH_LINENUMBER;"
        WriteBufLine MainTxtBuf, "        goto VWATCH_SETNEXTLINE;"
        WriteBufLine MainTxtBuf, "}"

        WriteBufLine MainTxtBuf, "VWATCH_SKIPLINE:;"
        WriteBufLine MainTxtBuf, "switch (*__LONG_VWATCH_GOTO) {"
        WriteBufLine MainTxtBuf, "#include " + CHR$(34) + "vw_main_skip.txt" + CHR$(34)
        WriteBufLine MainTxtBuf, "}"
    END IF

    WriteBufLine MainTxtBuf, "}"
    WriteBufLine RetTxtBuf, "}" 'end case
    WriteBufLine RetTxtBuf, "}"
    WriteBufLine RetTxtBuf, "error(3);" 'no valid return possible

    mainincbuf = OpenBuffer%("O", tmpdir$ + "main.txt")
    FOR i = 0 TO subfuncnlast
        WriteBufLine mainincbuf, "#include " + CHR$(34) + "main" + _TOSTR$(i) + ".txt" + CHR$(34)
    NEXT i
    WriteBufLine mainincbuf, "qbs *func__compdate() {"
    WriteBufLine mainincbuf, "return qbs_new_txt(__DATE__);"
    WriteBufLine mainincbuf, "}"
    WriteBufLine mainincbuf, "qbs *func__comptime() {"
    WriteBufLine mainincbuf, "return qbs_new_txt(__TIME__);"
    WriteBufLine mainincbuf, "}"
    WriteBufLine mainincbuf, "qbs *func__compvers() {"
    WriteBufLine mainincbuf, "return qbs_new_txt(" + CHR$(34) + "QB64-PE v" + Version$ + CHR$(34) + ");"
    WriteBufLine mainincbuf, "}"

    firstLineNumberLabelvWatch = 0
END SUB

FUNCTION countelements (a$)
    n = numelements(a$)
    c = 1
    FOR i = 1 TO n
        e$ = getelement$(a$, i)
        IF e$ = "(" THEN b = b + 1
        IF e$ = ")" THEN b = b - 1
        IF b < 0 THEN Give_Error "Unexpected ) encountered": EXIT FUNCTION
        IF e$ = "," AND b = 0 THEN c = c + 1
    NEXT
    countelements = c
END FUNCTION



FUNCTION dim2 (varname$, typ2$, method, elements$)

    'notes: (DO NOT REMOVE THESE IMPORTANT USAGE NOTES)
    '
    '(shared)dimsfarray: Creates an ID only (no C++ code)
    '                    Adds an index/'link' to the sub/function's argument
    '                        ID.sfid=glinkid
    '                        ID.sfarg=glinkarg
    '                    Sets arrayelements=-1 'unknown' (if elements$="?") otherwise val(elements$)
    '                    ***Does not refer to arrayelementslist()***
    '
    '(argument)method: 0 being created by a DIM name AS type
    '                  1 being created by a DIM name+symbol
    '                  or automatically without the use of DIM
    '
    'elements$="?": (see also dimsfarray for that special case)
    '               Checks arrayelementslist() and;
    '               if unknown(=0), creates an ID only
    '               if known, creates a DYNAMIC array's C++ initialization code so it can be used later

    typ$ = typ2$
    dim2 = 1 'success

    IF Debug THEN PRINT #9, "dim2 called", method

    cvarname$ = varname$
    l$ = cvarname$
    varname$ = UCASE$(varname$)

    IF dimsfarray = 1 THEN f = 0 ELSE f = 1

    IF dimstatic <> 0 AND dimshared = 0 THEN
        'name will have include the sub/func name in its scope
        'variable/array will be created in main on startup
        defdatahandle = GlobTxtBuf
        DataTxtBuf = OpenBuffer%("A", tmpdir$ + "maindata.txt")
        FreeTxtBuf = OpenBuffer%("A", tmpdir$ + "mainfree.txt")
    END IF


    scope2$ = module$ + "_" + subfunc$ + "_"
    'Note: when REDIMing a SHARED array in dynamic memory scope2$ must be modified

    IF LEN(typ$) = 0 THEN Give_Error "DIM2: No type specified!": EXIT FUNCTION

    'UDT
    'is it a udt?
    FOR i = 1 TO lasttype
        IF typ$ = RTRIM$(udtxname(i)) THEN
            dim2typepassback$ = RTRIM$(udtxcname(i))

            n$ = "UDT_" + varname$

            'array of UDTs
            IF elements$ <> "" THEN
                arraydesc = 0
                IF f = 1 THEN
                    try = findid(varname$)
                    IF Error_Happened THEN EXIT FUNCTION
                    DO WHILE try
                        IF (id.arraytype) THEN
                            l$ = RTRIM$(id.cn)
                            arraydesc = currentid: scope2$ = scope$
                            EXIT DO
                        END IF
                        IF try = 2 THEN findanotherid = 1: try = findid(varname$) ELSE try = 0
                        IF Error_Happened THEN EXIT FUNCTION
                    LOOP
                END IF
                n$ = scope2$ + "ARRAY_" + n$
                dynparammode = 0
                dyn_udt_mode = GetUDTCanonMode&(i)
                IF dimsfarray THEN
                    dynparammode = sf_udt_dynmode
                    IF dynparammode < 0 OR dynparammode > 1 THEN dynparammode = 0
                    'Parameter metadata is declaration-derived. A zero value is tolerated
                    'only as a compatibility fallback while rebuilding internal IDs.
                    IF dynparammode > 0 AND dynparammode <> dyn_udt_mode THEN
                        Give_Error "Internal TYPE parameter layout does not match its declaration": EXIT FUNCTION
                    END IF
                END IF
                bits = udtxsize(i)
                dyn_udt_layout = 0
                IF dyn_udt_mode > 0 THEN
                    IF UDTDynMembersOK%(i, dyn_udt_mode) = 0 THEN EXIT FUNCTION
                    bits = UDTDynLayoutSize&(i)
                    dyn_udt_layout = -1
                END IF

                IF f = 1 THEN

                    IF LEN(elements$) = 1 AND ASC(elements$) = 63 THEN '"?"
                        E = arrayelementslist(idn + 1): IF E THEN elements$ = elements$ + _TOSTR$(E) 'eg. "?3" for a 3 dimensional array
                    END IF
                    udt_alloc_dynmode = dyn_udt_mode
                    nume = allocarray(n$, elements$, bits \ 8, i)
                    udt_alloc_dynmode = 0
                    IF Error_Happened THEN EXIT FUNCTION
                    l$ = l$ + sp + tlayout$
                    IF arraydesc THEN
                        IF dyn_udt_layout THEN ids(arraydesc).dynudt = -1: ids(arraydesc).dynudtmode = dyn_udt_mode
                        GOTO dim2exitfunc
                    END IF
                    clearid

                ELSE
                    clearid
                    IF elements$ = "?" THEN
                        nume = -1
                        id.linkid = glinkid
                        id.linkarg = glinkarg
                    ELSE
                        nume = VAL(elements$)
                    END IF
                END IF

                id.arraytype = UDTTYPE + i
                IF dyn_udt_layout THEN id.dynudt = -1: id.dynudtmode = dyn_udt_mode
                IF cmemlist(idn + 1) THEN id.arraytype = id.arraytype + ISINCONVENTIONALMEMORY
                id.n = cvarname$

                IF nume > 65536 THEN nume = nume - 65536: id.staticarray = 1

                id.arrayelements = nume
                id.callname = n$
                regid
                vWatchVariable n$, 0
                IF Error_Happened THEN EXIT FUNCTION
                GOTO dim2exitfunc
            END IF

            'not an array of UDTs
            scalar_dyn_layout = 0
            scalar_dyn_mode = 0
            dynparammode = 0
            scalar_dyn_mode = GetUDTCanonMode&(i)
            IF dimsfarray THEN
                dynparammode = sf_udt_dynmode
                IF dynparammode < 0 OR dynparammode > 1 THEN dynparammode = 0
                IF dynparammode > 0 AND dynparammode <> scalar_dyn_mode THEN
                    Give_Error "Internal TYPE parameter layout does not match its declaration": EXIT FUNCTION
                END IF
            END IF
            bits = udtxsize(i)
            IF scalar_dyn_mode > 0 THEN
                IF UDTDynMembersOK%(i, scalar_dyn_mode) = 0 THEN EXIT FUNCTION
                bits = UDTDynLayoutSize&(i)
                scalar_dyn_layout = -1
            END IF
            bytes = bits \ 8
            IF bits MOD 8 THEN
                bytes = bytes + 1
            END IF
            n$ = scope2$ + n$
            IF f THEN WriteBufLine defdatahandle, "void *" + n$ + "=NULL;"
            clearid
            id.n = cvarname$
            id.t = UDTTYPE + i
            IF scalar_dyn_layout THEN id.dynudt = -1: id.dynudtmode = scalar_dyn_mode
            IF cmemlist(idn + 1) THEN
                id.t = id.t + ISINCONVENTIONALMEMORY
                IF f THEN
                    WriteBufLine DataTxtBuf, "if(" + n$ + "==NULL){"
                    WriteBufLine DataTxtBuf, "cmem_sp-=" + _TOSTR$(bytes) + ";"
                    WriteBufLine DataTxtBuf, "if (cmem_sp<qbs_cmem_sp) error(257);"
                    WriteBufLine DataTxtBuf, n$ + "=(void*)(dblock+cmem_sp);"
                    WriteBufLine DataTxtBuf, "memset(" + n$ + ",0," + _TOSTR$(bytes) + ");"
                    IF scalar_dyn_layout THEN
                        acc$ = ""
                        IF udtxvariable(i) THEN
                            ' A descriptor-layout scalar UDT may also own variable STRING slots.
                            ' Use the ownership-aware walker so qbs* members are initialized at
                            ' descriptor-layout offsets; the inline-layout walker could overwrite
                            ' descriptor slots when a _Dynamic member appears before a STRING.
                            AppendDynUDTOwnInitAt n$, i, 0, _TOSTR$(bytes), "0", acc$, scalar_dyn_mode
                        ELSE
                            AppendDynUDTDescInitAt n$, i, 0, _TOSTR$(bytes), "0", acc$, scalar_dyn_mode
                        END IF
                        IF Error_Happened THEN EXIT FUNCTION
                        WriteBufLine DataTxtBuf, acc$
                        acc$ = ""
                        IF udtxvariable(i) THEN
                            AppendDynUDTOwnFreeAt n$, i, 0, _TOSTR$(bytes), "0", acc$, scalar_dyn_mode
                        ELSE
                            AppendDynUDTDescFreeAt n$, i, 0, _TOSTR$(bytes), "0", acc$, scalar_dyn_mode
                        END IF
                        IF Error_Happened THEN EXIT FUNCTION
                        IF acc$ <> "" THEN WriteBufLine FreeTxtBuf, acc$
                    END IF
                    WriteBufLine DataTxtBuf, "}"
                END IF
            ELSE
                IF f THEN
                    WriteBufLine DataTxtBuf, "if(" + n$ + "==NULL){"
                    WriteBufLine DataTxtBuf, n$ + "=(void*)mem_static_malloc(" + _TOSTR$(bytes) + ");"
                    WriteBufLine DataTxtBuf, "memset(" + n$ + ",0," + _TOSTR$(bytes) + ");"
                    IF scalar_dyn_layout THEN
                        acc$ = ""
                        IF udtxvariable(i) THEN
                            ' A descriptor-layout scalar UDT may also own variable STRING slots.
                            ' Use the ownership-aware walker so qbs* members are initialized at
                            ' descriptor-layout offsets; the inline-layout walker could overwrite
                            ' descriptor slots when a _Dynamic member appears before a STRING.
                            AppendDynUDTOwnInitAt n$, i, 0, _TOSTR$(bytes), "0", acc$, scalar_dyn_mode
                        ELSE
                            AppendDynUDTDescInitAt n$, i, 0, _TOSTR$(bytes), "0", acc$, scalar_dyn_mode
                        END IF
                        IF Error_Happened THEN EXIT FUNCTION
                        WriteBufLine DataTxtBuf, acc$
                        acc$ = ""
                        IF udtxvariable(i) THEN
                            AppendDynUDTOwnFreeAt n$, i, 0, _TOSTR$(bytes), "0", acc$, scalar_dyn_mode
                        ELSE
                            AppendDynUDTDescFreeAt n$, i, 0, _TOSTR$(bytes), "0", acc$, scalar_dyn_mode
                        END IF
                        IF Error_Happened THEN EXIT FUNCTION
                        IF acc$ <> "" THEN WriteBufLine FreeTxtBuf, acc$
                    END IF
                    IF udtxvariable(i) AND scalar_dyn_layout = 0 THEN
                        initialise_udt_varstrings n$, i, DataTxtBuf, 0
                        free_udt_varstrings n$, i, FreeTxtBuf, 0
                    END IF
                    WriteBufLine DataTxtBuf, "}"
                END IF
            END IF
            id.callname = n$
            regid
            vWatchVariable n$, 0
            IF Error_Happened THEN EXIT FUNCTION
            GOTO dim2exitfunc
        END IF
    NEXT i
    'it isn't a udt

    typ$ = symbol2fulltypename$(typ$)
    IF Error_Happened THEN EXIT FUNCTION

    'check if _UNSIGNED was specified
    unsgn = 0
    IF LEFT$(typ$, 10) = "_UNSIGNED " THEN
        unsgn = 1
        typ$ = MID$(typ$, INSTR(typ$, CHR$(32)) + 1)
        IF LEN(typ$) = 0 THEN Give_Error "Expected more type information after _UNSIGNED!": EXIT FUNCTION
    END IF

    n$ = "" 'n$ is assumed to be "" after branching into the code for each type

    IF LEFT$(typ$, 6) = "STRING" THEN

        IF LEN(typ$) > 6 THEN
            IF LEFT$(typ$, 9) <> "STRING * " THEN Give_Error "Expected STRING * number/constant": EXIT FUNCTION

            c$ = RIGHT$(typ$, LEN(typ$) - 9)

            'constant check 2011
            hashfound = 0
            hashname$ = c$
            hashchkflags = HASHFLAG_CONSTANT
            hashres = HashFindRev(hashname$, hashchkflags, hashresflags, hashresref)
            DO WHILE hashres
                IF constsubfunc(hashresref) = subfuncn OR constsubfunc(hashresref) = 0 THEN
                    IF constdefined(hashresref) THEN
                        hashfound = 1
                        EXIT DO
                    END IF
                END IF
                IF hashres <> 1 THEN hashres = HashFindCont(hashresflags, hashresref) ELSE hashres = 0
            LOOP
            IF hashfound THEN
                i2 = hashresref
                t = consttype(i2)
                IF t AND ISSTRING THEN Give_Error "Expected STRING * numeric-constant": EXIT FUNCTION
                'convert value to general formats
                IF t AND ISFLOAT THEN
                    v## = constfloat(i2)
                    v&& = v##
                    v~&& = v&&
                ELSE
                    IF t AND ISUNSIGNED THEN
                        v~&& = constuinteger(i2)
                        v&& = v~&&
                        v## = v&&
                    ELSE
                        v&& = constinteger(i2)
                        v## = v&&
                        v~&& = v&&
                    END IF
                END IF
                IF v&& < 1 OR v&& > 9999999999 THEN Give_Error "STRING * out-of-range constant": EXIT FUNCTION
                bytes = v&&
                dim2typepassback$ = SCase$("String * ") + constcname(i2)
                GOTO constantlenstr
            END IF

            IF isuinteger(c$) = 0 THEN Give_Error "Number/Constant expected after *": EXIT FUNCTION
            IF LEN(c$) > 10 THEN Give_Error "Too many characters in number after *": EXIT FUNCTION
            bytes = VAL(c$)
            IF bytes = 0 THEN Give_Error "Cannot create a fixed string of length 0": EXIT FUNCTION
            constantlenstr:
            n$ = "STRING" + _TOSTR$(bytes) + "_" + varname$

            'array of fixed length strings
            IF elements$ <> "" THEN
                arraydesc = 0
                IF f = 1 THEN
                    try = findid(varname$ + "$")
                    IF Error_Happened THEN EXIT FUNCTION
                    DO WHILE try
                        IF (id.arraytype) THEN
                            ' Reject REDIM/DIM type changes between STRING and STRING * N arrays.
                            IF (id.arraytype AND ISSTRING) = 0 OR (id.arraytype AND ISFIXEDLENGTH) = 0 OR id.tsize <> bytes THEN Give_Error "Type mismatch": EXIT FUNCTION
                            l$ = RTRIM$(id.cn)
                            arraydesc = currentid: scope2$ = scope$
                            EXIT DO
                        END IF
                        IF try = 2 THEN findanotherid = 1: try = findid(varname$ + "$") ELSE try = 0
                        IF Error_Happened THEN EXIT FUNCTION
                    LOOP
                END IF
                n$ = scope2$ + "ARRAY_" + n$

                'nume = allocarray(n$, elements$, bytes)
                'IF arraydesc THEN goto dim2exitfunc 'id already exists!
                'clearid

                IF f = 1 THEN

                    IF LEN(elements$) = 1 AND ASC(elements$) = 63 THEN '"?"
                        E = arrayelementslist(idn + 1): IF E THEN elements$ = elements$ + _TOSTR$(E) 'eg. "?3" for a 3 dimensional array
                    END IF
                    nume = allocarray(n$, elements$, bytes, 0)
                    IF Error_Happened THEN EXIT FUNCTION
                    l$ = l$ + sp + tlayout$
                    IF arraydesc THEN GOTO dim2exitfunc
                    clearid

                ELSE
                    clearid
                    IF elements$ = "?" THEN
                        nume = -1
                        id.linkid = glinkid
                        id.linkarg = glinkarg
                    ELSE
                        nume = VAL(elements$)
                    END IF
                END IF

                id.arraytype = STRINGTYPE + ISFIXEDLENGTH
                IF cmemlist(idn + 1) THEN id.arraytype = id.arraytype + ISINCONVENTIONALMEMORY
                id.n = cvarname$
                IF nume > 65536 THEN nume = nume - 65536: id.staticarray = 1

                id.arrayelements = nume
                id.callname = n$
                id.tsize = bytes
                IF method = 0 THEN
                    id.mayhave = "$" + _TOSTR$(bytes)
                END IF
                IF method = 1 THEN
                    id.musthave = "$" + _TOSTR$(bytes)
                END IF
                regid
                IF Error_Happened THEN EXIT FUNCTION
                vWatchVariable n$, 0
                GOTO dim2exitfunc
            END IF

            'standard fixed length string
            n$ = scope2$ + n$
            IF f THEN WriteBufLine defdatahandle, "qbs *" + n$ + "=NULL;"
            IF f THEN WriteBufLine FreeTxtBuf, "qbs_free(" + n$ + ");" 'so descriptor can be freed
            clearid
            id.n = cvarname$
            id.t = STRINGTYPE + ISFIXEDLENGTH
            IF cmemlist(idn + 1) THEN
                id.t = id.t + ISINCONVENTIONALMEMORY
                IF f THEN WriteBufLine DataTxtBuf, "if(" + n$ + "==NULL){"
                IF f THEN WriteBufLine DataTxtBuf, "cmem_sp-=" + _TOSTR$(bytes) + ";"
                IF f THEN WriteBufLine DataTxtBuf, "if (cmem_sp<qbs_cmem_sp) error(257);"
                IF f THEN WriteBufLine DataTxtBuf, n$ + "=qbs_new_fixed((uint8*)(dblock+cmem_sp)," + _TOSTR$(bytes) + ",0);"
                IF f THEN WriteBufLine DataTxtBuf, "memset(" + n$ + "->chr,0," + _TOSTR$(bytes) + ");"
                IF f THEN WriteBufLine DataTxtBuf, "}"
            ELSE
                IF f THEN WriteBufLine DataTxtBuf, "if(" + n$ + "==NULL){"
                o$ = "(uint8*)mem_static_malloc(" + _TOSTR$(bytes) + ")"
                IF f THEN WriteBufLine DataTxtBuf, n$ + "=qbs_new_fixed(" + o$ + "," + _TOSTR$(bytes) + ",0);"
                IF f THEN WriteBufLine DataTxtBuf, "memset(" + n$ + "->chr,0," + _TOSTR$(bytes) + ");"
                IF f THEN WriteBufLine DataTxtBuf, "}"
            END IF
            id.tsize = bytes
            IF method = 0 THEN
                id.mayhave = "$" + _TOSTR$(bytes)
            END IF
            IF method = 1 THEN
                id.musthave = "$" + _TOSTR$(bytes)
            END IF
            id.callname = n$
            regid
            vWatchVariable n$, 0
            IF Error_Happened THEN EXIT FUNCTION
            GOTO dim2exitfunc
        END IF

        'variable length string processing
        n$ = "STRING_" + varname$

        'array of variable length strings
        IF elements$ <> "" THEN
            arraydesc = 0
            IF f = 1 THEN
                try = findid(varname$ + "$")
                IF Error_Happened THEN EXIT FUNCTION
                DO WHILE try
                    IF (id.arraytype) THEN
                        ' Reject REDIM/DIM type changes between STRING and STRING * N arrays.
                        IF (id.arraytype AND ISSTRING) = 0 OR (id.arraytype AND ISFIXEDLENGTH) <> 0 THEN Give_Error "Type mismatch": EXIT FUNCTION
                        l$ = RTRIM$(id.cn)
                        arraydesc = currentid: scope2$ = scope$
                        EXIT DO
                    END IF
                    IF try = 2 THEN findanotherid = 1: try = findid(varname$ + "$") ELSE try = 0
                    IF Error_Happened THEN EXIT FUNCTION
                LOOP
            END IF
            n$ = scope2$ + "ARRAY_" + n$

            'nume = allocarray(n$, elements$, -2147483647) '-2147483647=STRING
            'IF arraydesc THEN goto dim2exitfunc 'id already exists!
            'clearid

            IF f = 1 THEN

                IF LEN(elements$) = 1 AND ASC(elements$) = 63 THEN '"?"
                    E = arrayelementslist(idn + 1): IF E THEN elements$ = elements$ + _TOSTR$(E) 'eg. "?3" for a 3 dimensional array
                END IF
                nume = allocarray(n$, elements$, -2147483647, 0)
                IF Error_Happened THEN EXIT FUNCTION
                l$ = l$ + sp + tlayout$
                IF arraydesc THEN GOTO dim2exitfunc
                clearid

            ELSE
                clearid
                IF elements$ = "?" THEN
                    nume = -1
                    id.linkid = glinkid
                    id.linkarg = glinkarg
                ELSE
                    nume = VAL(elements$)
                END IF
            END IF

            id.n = cvarname$
            id.arraytype = STRINGTYPE
            IF cmemlist(idn + 1) THEN id.arraytype = id.arraytype + ISINCONVENTIONALMEMORY
            IF nume > 65536 THEN nume = nume - 65536: id.staticarray = 1

            id.arrayelements = nume
            id.callname = n$
            IF method = 0 THEN
                id.mayhave = "$"
            END IF
            IF method = 1 THEN
                id.musthave = "$"
            END IF
            regid
            IF Error_Happened THEN EXIT FUNCTION
            vWatchVariable n$, 0
            GOTO dim2exitfunc
        END IF

        'standard variable length string
        n$ = scope2$ + n$
        clearid
        id.n = cvarname$
        id.t = STRINGTYPE
        IF cmemlist(idn + 1) THEN
            IF f THEN WriteBufLine defdatahandle, "qbs *" + n$ + "=NULL;"
            IF f THEN WriteBufLine DataTxtBuf, "if (!" + n$ + ")" + n$ + "=qbs_new_cmem(0,0);"
            id.t = id.t + ISINCONVENTIONALMEMORY
        ELSE
            IF f THEN WriteBufLine defdatahandle, "qbs *" + n$ + "=NULL;"
            IF f THEN WriteBufLine DataTxtBuf, "if (!" + n$ + ")" + n$ + "=qbs_new(0,0);"
        END IF
        IF f THEN WriteBufLine FreeTxtBuf, "qbs_free(" + n$ + ");"
        IF method = 0 THEN
            id.mayhave = "$"
        END IF
        IF method = 1 THEN
            id.musthave = "$"
        END IF
        id.callname = n$
        regid
        vWatchVariable n$, 0
        IF Error_Happened THEN EXIT FUNCTION
        GOTO dim2exitfunc
    END IF

    IF LEFT$(typ$, 4) = "_BIT" THEN
        IF LEFT$(typ$, 4) = "_BIT" AND LEN(typ$) > 4 THEN
            IF LEFT$(typ$, 7) <> "_BIT * " THEN Give_Error "Expected _BIT * number": EXIT FUNCTION
            c$ = MID$(typ$, INSTR(typ$, " * ") + 3)
            IF isuinteger(c$) = 0 THEN Give_Error "Number expected after *": EXIT FUNCTION
            IF LEN(c$) > 2 THEN Give_Error "Cannot create a _BIT variable of size > 64 bits": EXIT FUNCTION
            bits = VAL(c$)
            IF bits = 0 THEN Give_Error "Cannot create a _BIT variable of size 0 bits": EXIT FUNCTION
            IF bits > 64 THEN Give_Error "Cannot create a _BIT variable of size > 64 bits": EXIT FUNCTION
        ELSE
            bits = 1
        END IF
        IF bits <= 32 THEN ct$ = "int32" ELSE ct$ = "int64"
        IF unsgn THEN n$ = "U": ct$ = "u" + ct$
        n$ = n$ + "BIT" + _TOSTR$(bits) + "_" + varname$

        'array of bit-length variables
        IF elements$ <> "" THEN
            IF bits > 63 THEN Give_Error "Cannot create a _BIT array of size > 63 bits": EXIT FUNCTION
            arraydesc = 0
            cmps$ = varname$: IF unsgn THEN cmps$ = cmps$ + "~"
            cmps$ = cmps$ + "`" + _TOSTR$(bits)
            IF f = 1 THEN
                try = findid(cmps$)
                IF Error_Happened THEN EXIT FUNCTION
                DO WHILE try
                    IF (id.arraytype) THEN
                        l$ = RTRIM$(id.cn)
                        arraydesc = currentid: scope2$ = scope$
                        EXIT DO
                    END IF
                    IF try = 2 THEN findanotherid = 1: try = findid(cmps$) ELSE try = 0
                    IF Error_Happened THEN EXIT FUNCTION
                LOOP
            END IF
            n$ = scope2$ + "ARRAY_" + n$

            'nume = allocarray(n$, elements$, -bits) 'passing a negative element size signifies bits not bytes
            'IF arraydesc THEN goto dim2exitfunc 'id already exists!
            'clearid

            IF f = 1 THEN

                IF LEN(elements$) = 1 AND ASC(elements$) = 63 THEN '"?"
                    E = arrayelementslist(idn + 1): IF E THEN elements$ = elements$ + _TOSTR$(E) 'eg. "?3" for a 3 dimensional array
                END IF
                nume = allocarray(n$, elements$, -bits, 0)
                IF Error_Happened THEN EXIT FUNCTION
                l$ = l$ + sp + tlayout$
                IF arraydesc THEN GOTO dim2exitfunc
                clearid

            ELSE
                clearid
                IF elements$ = "?" THEN
                    nume = -1
                    id.linkid = glinkid
                    id.linkarg = glinkarg
                ELSE
                    nume = VAL(elements$)
                END IF
            END IF

            id.n = cvarname$
            id.arraytype = BITTYPE - 1 + bits
            IF unsgn THEN id.arraytype = id.arraytype + ISUNSIGNED
            IF cmemlist(idn + 1) THEN id.arraytype = id.arraytype + ISINCONVENTIONALMEMORY
            IF nume > 65536 THEN nume = nume - 65536: id.staticarray = 1

            id.arrayelements = nume
            id.callname = n$
            IF method = 0 THEN
                IF unsgn THEN id.mayhave = "~`" + _TOSTR$(bits) ELSE id.mayhave = "`" + _TOSTR$(bits)
            END IF
            IF method = 1 THEN
                IF unsgn THEN id.musthave = "~`" + _TOSTR$(bits) ELSE id.musthave = "`" + _TOSTR$(bits)
            END IF
            regid
            IF Error_Happened THEN EXIT FUNCTION
            vWatchVariable n$, 0
            GOTO dim2exitfunc
        END IF
        'standard bit-length variable
        n$ = scope2$ + n$
        WriteBufLine defdatahandle, ct$ + " *" + n$ + "=NULL;"
        WriteBufLine DataTxtBuf, "if(" + n$ + "==NULL){"
        WriteBufLine DataTxtBuf, "cmem_sp-=4;"
        WriteBufLine DataTxtBuf, "if (cmem_sp<qbs_cmem_sp) error(257);"
        WriteBufLine DataTxtBuf, n$ + "=(" + ct$ + "*)(dblock+cmem_sp);"
        WriteBufLine DataTxtBuf, "*" + n$ + "=0;"
        WriteBufLine DataTxtBuf, "}"
        clearid
        id.n = cvarname$
        id.t = BITTYPE - 1 + bits + ISINCONVENTIONALMEMORY: IF unsgn THEN id.t = id.t + ISUNSIGNED
        IF method = 0 THEN
            IF unsgn THEN id.mayhave = "~`" + _TOSTR$(bits) ELSE id.mayhave = "`" + _TOSTR$(bits)
        END IF
        IF method = 1 THEN
            IF unsgn THEN id.musthave = "~`" + _TOSTR$(bits) ELSE id.musthave = "`" + _TOSTR$(bits)
        END IF
        id.callname = n$
        regid
        vWatchVariable n$, 0
        IF Error_Happened THEN EXIT FUNCTION
        GOTO dim2exitfunc
    END IF

    IF typ$ = "_BYTE" THEN
        ct$ = "int8"
        IF unsgn THEN n$ = "U": ct$ = "u" + ct$
        n$ = n$ + "BYTE_" + varname$
        IF elements$ <> "" THEN
            arraydesc = 0
            cmps$ = varname$: IF unsgn THEN cmps$ = cmps$ + "~"
            cmps$ = cmps$ + "%%"
            IF f = 1 THEN
                try = findid(cmps$)
                IF Error_Happened THEN EXIT FUNCTION
                DO WHILE try
                    IF (id.arraytype) THEN
                        l$ = RTRIM$(id.cn)
                        arraydesc = currentid: scope2$ = scope$
                        EXIT DO
                    END IF
                    IF try = 2 THEN findanotherid = 1: try = findid(cmps$) ELSE try = 0
                    IF Error_Happened THEN EXIT FUNCTION
                LOOP

            END IF
            n$ = scope2$ + "ARRAY_" + n$

            'nume = allocarray(n$, elements$, 1)
            'IF arraydesc THEN goto dim2exitfunc
            'clearid

            IF f = 1 THEN

                IF LEN(elements$) = 1 AND ASC(elements$) = 63 THEN '"?"
                    E = arrayelementslist(idn + 1): IF E THEN elements$ = elements$ + _TOSTR$(E) 'eg. "?3" for a 3 dimensional array
                END IF
                nume = allocarray(n$, elements$, 1, 0)
                IF Error_Happened THEN EXIT FUNCTION
                l$ = l$ + sp + tlayout$
                IF arraydesc THEN GOTO dim2exitfunc
                clearid

            ELSE
                clearid
                IF elements$ = "?" THEN
                    nume = -1
                    id.linkid = glinkid
                    id.linkarg = glinkarg
                ELSE
                    nume = VAL(elements$)
                END IF
            END IF

            id.arraytype = BYTETYPE: IF unsgn THEN id.arraytype = id.arraytype + ISUNSIGNED
            IF cmemlist(idn + 1) THEN id.arraytype = id.arraytype + ISINCONVENTIONALMEMORY
            IF nume > 65536 THEN nume = nume - 65536: id.staticarray = 1

            id.arrayelements = nume
            id.callname = n$
        ELSE
            n$ = scope2$ + n$
            clearid
            id.t = BYTETYPE: IF unsgn THEN id.t = id.t + ISUNSIGNED
            IF f = 1 THEN WriteBufLine defdatahandle, ct$ + " *" + n$ + "=NULL;"
            IF f = 1 THEN WriteBufLine DataTxtBuf, "if(" + n$ + "==NULL){"
            IF cmemlist(idn + 1) THEN
                id.t = id.t + ISINCONVENTIONALMEMORY
                IF f = 1 THEN WriteBufLine DataTxtBuf, "cmem_sp-=1;"
                IF f = 1 THEN WriteBufLine DataTxtBuf, n$ + "=(" + ct$ + "*)(dblock+cmem_sp);"
                IF f = 1 THEN WriteBufLine DataTxtBuf, "if (cmem_sp<qbs_cmem_sp) error(257);"
            ELSE
                IF f = 1 THEN WriteBufLine DataTxtBuf, n$ + "=(" + ct$ + "*)mem_static_malloc(1);"
            END IF
            IF f = 1 THEN WriteBufLine DataTxtBuf, "*" + n$ + "=0;"
            IF f = 1 THEN WriteBufLine DataTxtBuf, "}"
        END IF
        id.n = cvarname$
        IF method = 0 THEN
            IF unsgn THEN id.mayhave = "~%%" ELSE id.mayhave = "%%"
        END IF
        IF method = 1 THEN
            IF unsgn THEN id.musthave = "~%%" ELSE id.musthave = "%%"
        END IF
        id.callname = n$
        regid
        vWatchVariable n$, 0
        IF Error_Happened THEN EXIT FUNCTION
        GOTO dim2exitfunc
    END IF

    IF typ$ = "INTEGER" THEN
        ct$ = "int16"
        IF unsgn THEN n$ = "U": ct$ = "u" + ct$
        n$ = n$ + "INTEGER_" + varname$

        IF elements$ <> "" THEN
            arraydesc = 0
            cmps$ = varname$: IF unsgn THEN cmps$ = cmps$ + "~"
            cmps$ = cmps$ + "%"
            IF f = 1 THEN
                try = findid(cmps$)
                IF Error_Happened THEN EXIT FUNCTION
                DO WHILE try
                    IF (id.arraytype) THEN
                        l$ = RTRIM$(id.cn)
                        arraydesc = currentid: scope2$ = scope$
                        EXIT DO
                    END IF
                    IF try = 2 THEN findanotherid = 1: try = findid(cmps$) ELSE try = 0
                    IF Error_Happened THEN EXIT FUNCTION
                LOOP
            END IF
            n$ = scope2$ + "ARRAY_" + n$

            IF f = 1 THEN

                IF LEN(elements$) = 1 AND ASC(elements$) = 63 THEN '"?"
                    E = arrayelementslist(idn + 1): IF E THEN elements$ = elements$ + _TOSTR$(E) 'eg. "?3" for a 3 dimensional array
                END IF
                nume = allocarray(n$, elements$, 2, 0)
                IF Error_Happened THEN EXIT FUNCTION
                l$ = l$ + sp + tlayout$
                IF arraydesc THEN GOTO dim2exitfunc
                clearid

            ELSE
                clearid
                IF elements$ = "?" THEN
                    nume = -1
                    id.linkid = glinkid
                    id.linkarg = glinkarg
                ELSE
                    nume = VAL(elements$)
                END IF
            END IF


            id.arraytype = INTEGERTYPE: IF unsgn THEN id.arraytype = id.arraytype + ISUNSIGNED
            IF cmemlist(idn + 1) THEN id.arraytype = id.arraytype + ISINCONVENTIONALMEMORY
            IF nume > 65536 THEN nume = nume - 65536: id.staticarray = 1

            id.arrayelements = nume
            id.callname = n$
        ELSE
            n$ = scope2$ + n$
            clearid
            id.t = INTEGERTYPE: IF unsgn THEN id.t = id.t + ISUNSIGNED
            IF f = 1 THEN WriteBufLine defdatahandle, ct$ + " *" + n$ + "=NULL;"
            IF f = 1 THEN WriteBufLine DataTxtBuf, "if(" + n$ + "==NULL){"
            IF cmemlist(idn + 1) THEN
                id.t = id.t + ISINCONVENTIONALMEMORY
                IF f = 1 THEN WriteBufLine DataTxtBuf, "cmem_sp-=2;"
                IF f = 1 THEN WriteBufLine DataTxtBuf, n$ + "=(" + ct$ + "*)(dblock+cmem_sp);"
                IF f = 1 THEN WriteBufLine DataTxtBuf, "if (cmem_sp<qbs_cmem_sp) error(257);"
            ELSE
                IF f = 1 THEN WriteBufLine DataTxtBuf, n$ + "=(" + ct$ + "*)mem_static_malloc(2);"
            END IF
            IF f = 1 THEN WriteBufLine DataTxtBuf, "*" + n$ + "=0;"
            IF f = 1 THEN WriteBufLine DataTxtBuf, "}"
        END IF
        id.n = cvarname$
        IF method = 0 THEN
            IF unsgn THEN id.mayhave = "~%" ELSE id.mayhave = "%"
        END IF
        IF method = 1 THEN
            IF unsgn THEN id.musthave = "~%" ELSE id.musthave = "%"
        END IF
        id.callname = n$
        regid
        vWatchVariable n$, 0
        IF Error_Happened THEN EXIT FUNCTION
        GOTO dim2exitfunc
    END IF








    IF typ$ = "_OFFSET" THEN
        ct$ = "ptrszint"
        IF unsgn THEN n$ = "U": ct$ = "u" + ct$
        n$ = n$ + "OFFSET_" + varname$
        IF elements$ <> "" THEN
            arraydesc = 0
            cmps$ = varname$: IF unsgn THEN cmps$ = cmps$ + "~"
            cmps$ = cmps$ + "%&"
            IF f = 1 THEN
                try = findid(cmps$)
                IF Error_Happened THEN EXIT FUNCTION
                DO WHILE try
                    IF (id.arraytype) THEN
                        l$ = RTRIM$(id.cn)
                        arraydesc = currentid: scope2$ = scope$
                        EXIT DO
                    END IF
                    IF try = 2 THEN findanotherid = 1: try = findid(cmps$) ELSE try = 0
                    IF Error_Happened THEN EXIT FUNCTION
                LOOP
            END IF
            n$ = scope2$ + "ARRAY_" + n$

            IF f = 1 THEN

                IF LEN(elements$) = 1 AND ASC(elements$) = 63 THEN '"?"
                    E = arrayelementslist(idn + 1): IF E THEN elements$ = elements$ + _TOSTR$(E) 'eg. "?3" for a 3 dimensional array
                END IF
                nume = allocarray(n$, elements$, OS_BITS \ 8, 0)
                IF Error_Happened THEN EXIT FUNCTION
                l$ = l$ + sp + tlayout$
                IF arraydesc THEN GOTO dim2exitfunc
                clearid

            ELSE
                clearid
                IF elements$ = "?" THEN
                    nume = -1
                    id.linkid = glinkid
                    id.linkarg = glinkarg
                ELSE
                    nume = VAL(elements$)
                END IF
            END IF

            id.arraytype = OFFSETTYPE: IF unsgn THEN id.arraytype = id.arraytype + ISUNSIGNED
            IF cmemlist(idn + 1) THEN id.arraytype = id.arraytype + ISINCONVENTIONALMEMORY
            IF nume > 65536 THEN nume = nume - 65536: id.staticarray = 1

            id.arrayelements = nume
            id.callname = n$
        ELSE
            n$ = scope2$ + n$
            clearid
            id.t = OFFSETTYPE: IF unsgn THEN id.t = id.t + ISUNSIGNED
            IF f = 1 THEN WriteBufLine defdatahandle, ct$ + " *" + n$ + "=NULL;"
            IF f = 1 THEN WriteBufLine DataTxtBuf, "if(" + n$ + "==NULL){"
            IF cmemlist(idn + 1) THEN
                id.t = id.t + ISINCONVENTIONALMEMORY
                IF f = 1 THEN WriteBufLine DataTxtBuf, "cmem_sp-=" + _TOSTR$(OS_BITS \ 8) + ";"
                IF f = 1 THEN WriteBufLine DataTxtBuf, n$ + "=(" + ct$ + "*)(dblock+cmem_sp);"
                IF f = 1 THEN WriteBufLine DataTxtBuf, "if (cmem_sp<qbs_cmem_sp) error(257);"
            ELSE
                IF f = 1 THEN WriteBufLine DataTxtBuf, n$ + "=(" + ct$ + "*)mem_static_malloc(" + _TOSTR$(OS_BITS \ 8) + ");"
            END IF
            IF f = 1 THEN WriteBufLine DataTxtBuf, "*" + n$ + "=0;"
            IF f = 1 THEN WriteBufLine DataTxtBuf, "}"
        END IF
        id.n = cvarname$
        IF method = 0 THEN
            IF unsgn THEN id.mayhave = "~%&" ELSE id.mayhave = "%&"
        END IF
        IF method = 1 THEN
            IF unsgn THEN id.musthave = "~%&" ELSE id.musthave = "%&"
        END IF
        id.callname = n$
        regid
        vWatchVariable n$, 0
        IF Error_Happened THEN EXIT FUNCTION
        GOTO dim2exitfunc
    END IF

    IF typ$ = "LONG" THEN
        ct$ = "int32"
        IF unsgn THEN n$ = "U": ct$ = "u" + ct$
        n$ = n$ + "LONG_" + varname$
        IF elements$ <> "" THEN
            arraydesc = 0
            cmps$ = varname$: IF unsgn THEN cmps$ = cmps$ + "~"
            cmps$ = cmps$ + "&"
            IF f = 1 THEN
                try = findid(cmps$)
                IF Error_Happened THEN EXIT FUNCTION
                DO WHILE try
                    IF (id.arraytype) THEN
                        l$ = RTRIM$(id.cn)
                        arraydesc = currentid: scope2$ = scope$
                        EXIT DO
                    END IF
                    IF try = 2 THEN findanotherid = 1: try = findid(cmps$) ELSE try = 0
                    IF Error_Happened THEN EXIT FUNCTION
                LOOP
            END IF
            n$ = scope2$ + "ARRAY_" + n$

            'nume = allocarray(n$, elements$, 4)
            'IF arraydesc THEN goto dim2exitfunc
            'clearid

            IF f = 1 THEN

                IF LEN(elements$) = 1 AND ASC(elements$) = 63 THEN '"?"
                    E = arrayelementslist(idn + 1): IF E THEN elements$ = elements$ + _TOSTR$(E) 'eg. "?3" for a 3 dimensional array
                END IF
                nume = allocarray(n$, elements$, 4, 0)
                IF Error_Happened THEN EXIT FUNCTION
                l$ = l$ + sp + tlayout$
                IF arraydesc THEN GOTO dim2exitfunc
                clearid

            ELSE
                clearid
                IF elements$ = "?" THEN
                    nume = -1
                    id.linkid = glinkid
                    id.linkarg = glinkarg
                ELSE
                    nume = VAL(elements$)
                END IF
            END IF

            id.arraytype = LONGTYPE: IF unsgn THEN id.arraytype = id.arraytype + ISUNSIGNED
            IF cmemlist(idn + 1) THEN id.arraytype = id.arraytype + ISINCONVENTIONALMEMORY
            IF nume > 65536 THEN nume = nume - 65536: id.staticarray = 1

            id.arrayelements = nume
            id.callname = n$
        ELSE
            n$ = scope2$ + n$
            clearid
            id.t = LONGTYPE: IF unsgn THEN id.t = id.t + ISUNSIGNED
            IF f = 1 THEN WriteBufLine defdatahandle, ct$ + " *" + n$ + "=NULL;"
            IF f = 1 THEN WriteBufLine DataTxtBuf, "if(" + n$ + "==NULL){"
            IF cmemlist(idn + 1) THEN
                id.t = id.t + ISINCONVENTIONALMEMORY
                IF f = 1 THEN WriteBufLine DataTxtBuf, "cmem_sp-=4;"
                IF f = 1 THEN WriteBufLine DataTxtBuf, n$ + "=(" + ct$ + "*)(dblock+cmem_sp);"
                IF f = 1 THEN WriteBufLine DataTxtBuf, "if (cmem_sp<qbs_cmem_sp) error(257);"
            ELSE
                IF f = 1 THEN WriteBufLine DataTxtBuf, n$ + "=(" + ct$ + "*)mem_static_malloc(4);"
            END IF
            IF f = 1 THEN WriteBufLine DataTxtBuf, "*" + n$ + "=0;"
            IF f = 1 THEN WriteBufLine DataTxtBuf, "}"
        END IF
        id.n = cvarname$
        IF method = 0 THEN
            IF unsgn THEN id.mayhave = "~&" ELSE id.mayhave = "&"
        END IF
        IF method = 1 THEN
            IF unsgn THEN id.musthave = "~&" ELSE id.musthave = "&"
        END IF
        id.callname = n$
        regid
        vWatchVariable n$, 0
        IF Error_Happened THEN EXIT FUNCTION
        GOTO dim2exitfunc
    END IF

    IF typ$ = "_INTEGER64" THEN
        ct$ = "int64"
        IF unsgn THEN n$ = "U": ct$ = "u" + ct$
        n$ = n$ + "INTEGER64_" + varname$
        IF elements$ <> "" THEN
            arraydesc = 0
            cmps$ = varname$: IF unsgn THEN cmps$ = cmps$ + "~"
            cmps$ = cmps$ + "&&"
            IF f = 1 THEN
                try = findid(cmps$)
                IF Error_Happened THEN EXIT FUNCTION
                DO WHILE try
                    IF (id.arraytype) THEN
                        l$ = RTRIM$(id.cn)
                        arraydesc = currentid: scope2$ = scope$
                        EXIT DO
                    END IF
                    IF try = 2 THEN findanotherid = 1: try = findid(cmps$) ELSE try = 0
                    IF Error_Happened THEN EXIT FUNCTION
                LOOP
            END IF
            n$ = scope2$ + "ARRAY_" + n$

            'nume = allocarray(n$, elements$, 8)
            'IF arraydesc THEN goto dim2exitfunc
            'clearid

            IF f = 1 THEN

                IF LEN(elements$) = 1 AND ASC(elements$) = 63 THEN '"?"
                    E = arrayelementslist(idn + 1): IF E THEN elements$ = elements$ + _TOSTR$(E) 'eg. "?3" for a 3 dimensional array
                END IF
                nume = allocarray(n$, elements$, 8, 0)
                IF Error_Happened THEN EXIT FUNCTION
                l$ = l$ + sp + tlayout$
                IF arraydesc THEN GOTO dim2exitfunc
                clearid

            ELSE
                clearid
                IF elements$ = "?" THEN
                    nume = -1
                    id.linkid = glinkid
                    id.linkarg = glinkarg
                ELSE
                    nume = VAL(elements$)
                END IF
            END IF

            id.arraytype = INTEGER64TYPE: IF unsgn THEN id.arraytype = id.arraytype + ISUNSIGNED
            IF cmemlist(idn + 1) THEN id.arraytype = id.arraytype + ISINCONVENTIONALMEMORY
            IF nume > 65536 THEN nume = nume - 65536: id.staticarray = 1

            id.arrayelements = nume
            id.callname = n$
        ELSE
            n$ = scope2$ + n$
            clearid
            id.t = INTEGER64TYPE: IF unsgn THEN id.t = id.t + ISUNSIGNED
            IF f = 1 THEN WriteBufLine defdatahandle, ct$ + " *" + n$ + "=NULL;"
            IF f = 1 THEN WriteBufLine DataTxtBuf, "if(" + n$ + "==NULL){"
            IF cmemlist(idn + 1) THEN
                id.t = id.t + ISINCONVENTIONALMEMORY
                IF f = 1 THEN WriteBufLine DataTxtBuf, "cmem_sp-=8;"
                IF f = 1 THEN WriteBufLine DataTxtBuf, n$ + "=(" + ct$ + "*)(dblock+cmem_sp);"
                IF f = 1 THEN WriteBufLine DataTxtBuf, "if (cmem_sp<qbs_cmem_sp) error(257);"
            ELSE
                IF f = 1 THEN WriteBufLine DataTxtBuf, n$ + "=(" + ct$ + "*)mem_static_malloc(8);"
            END IF
            IF f = 1 THEN WriteBufLine DataTxtBuf, "*" + n$ + "=0;"
            IF f = 1 THEN WriteBufLine DataTxtBuf, "}"
        END IF
        id.n = cvarname$
        IF method = 0 THEN
            IF unsgn THEN id.mayhave = "~&&" ELSE id.mayhave = "&&"
        END IF
        IF method = 1 THEN
            IF unsgn THEN id.musthave = "~&&" ELSE id.musthave = "&&"
        END IF
        id.callname = n$
        regid
        vWatchVariable n$, 0
        IF Error_Happened THEN EXIT FUNCTION
        GOTO dim2exitfunc
    END IF

    IF unsgn = 1 THEN Give_Error "Type cannot be _UNSIGNED": EXIT FUNCTION

    IF typ$ = "SINGLE" THEN
        ct$ = "float"
        n$ = n$ + "SINGLE_" + varname$
        IF elements$ <> "" THEN
            arraydesc = 0
            cmps$ = varname$ + "!"
            IF f = 1 THEN
                try = findid(cmps$)
                IF Error_Happened THEN EXIT FUNCTION
                DO WHILE try
                    IF (id.arraytype) THEN
                        l$ = RTRIM$(id.cn)
                        arraydesc = currentid: scope2$ = scope$
                        EXIT DO
                    END IF
                    IF try = 2 THEN findanotherid = 1: try = findid(cmps$) ELSE try = 0
                    IF Error_Happened THEN EXIT FUNCTION
                LOOP
            END IF
            n$ = scope2$ + "ARRAY_" + n$

            'nume = allocarray(n$, elements$, 4)
            'IF arraydesc THEN goto dim2exitfunc
            'clearid

            IF f = 1 THEN

                IF LEN(elements$) = 1 AND ASC(elements$) = 63 THEN '"?"
                    E = arrayelementslist(idn + 1): IF E THEN elements$ = elements$ + _TOSTR$(E) 'eg. "?3" for a 3 dimensional array
                END IF
                nume = allocarray(n$, elements$, 4, 0)
                IF Error_Happened THEN EXIT FUNCTION
                l$ = l$ + sp + tlayout$
                IF arraydesc THEN GOTO dim2exitfunc
                clearid

            ELSE
                clearid
                IF elements$ = "?" THEN
                    nume = -1
                    id.linkid = glinkid
                    id.linkarg = glinkarg
                ELSE
                    nume = VAL(elements$)
                END IF
            END IF

            id.arraytype = SINGLETYPE
            IF cmemlist(idn + 1) THEN id.arraytype = id.arraytype + ISINCONVENTIONALMEMORY
            IF nume > 65536 THEN nume = nume - 65536: id.staticarray = 1

            id.arrayelements = nume
            id.callname = n$
        ELSE
            n$ = scope2$ + n$
            clearid
            id.t = SINGLETYPE
            IF f = 1 THEN WriteBufLine defdatahandle, ct$ + " *" + n$ + "=NULL;"
            IF f = 1 THEN WriteBufLine DataTxtBuf, "if(" + n$ + "==NULL){"
            IF cmemlist(idn + 1) THEN
                id.t = id.t + ISINCONVENTIONALMEMORY
                IF f = 1 THEN WriteBufLine DataTxtBuf, "cmem_sp-=4;"
                IF f = 1 THEN WriteBufLine DataTxtBuf, n$ + "=(" + ct$ + "*)(dblock+cmem_sp);"
                IF f = 1 THEN WriteBufLine DataTxtBuf, "if (cmem_sp<qbs_cmem_sp) error(257);"
            ELSE
                IF f = 1 THEN WriteBufLine DataTxtBuf, n$ + "=(" + ct$ + "*)mem_static_malloc(4);"
            END IF
            IF f = 1 THEN WriteBufLine DataTxtBuf, "*" + n$ + "=0;"
            IF f = 1 THEN WriteBufLine DataTxtBuf, "}"
        END IF
        id.n = cvarname$
        IF method = 0 THEN
            id.mayhave = "!"
        END IF
        IF method = 1 THEN
            id.musthave = "!"
        END IF
        id.callname = n$
        regid
        vWatchVariable n$, 0
        IF Error_Happened THEN EXIT FUNCTION
        GOTO dim2exitfunc
    END IF

    IF typ$ = "DOUBLE" THEN
        ct$ = "double"
        n$ = n$ + "DOUBLE_" + varname$
        IF elements$ <> "" THEN
            arraydesc = 0
            cmps$ = varname$ + "#"
            IF f = 1 THEN
                try = findid(cmps$)
                IF Error_Happened THEN EXIT FUNCTION
                DO WHILE try
                    IF (id.arraytype) THEN
                        l$ = RTRIM$(id.cn)
                        arraydesc = currentid: scope2$ = scope$
                        EXIT DO
                    END IF
                    IF try = 2 THEN findanotherid = 1: try = findid(cmps$) ELSE try = 0
                    IF Error_Happened THEN EXIT FUNCTION
                LOOP
            END IF
            n$ = scope2$ + "ARRAY_" + n$

            'nume = allocarray(n$, elements$, 8)
            'IF arraydesc THEN goto dim2exitfunc
            'clearid

            IF f = 1 THEN

                IF LEN(elements$) = 1 AND ASC(elements$) = 63 THEN '"?"
                    E = arrayelementslist(idn + 1): IF E THEN elements$ = elements$ + _TOSTR$(E) 'eg. "?3" for a 3 dimensional array
                END IF
                nume = allocarray(n$, elements$, 8, 0)
                IF Error_Happened THEN EXIT FUNCTION
                l$ = l$ + sp + tlayout$
                IF arraydesc THEN GOTO dim2exitfunc
                clearid

            ELSE
                clearid
                IF elements$ = "?" THEN
                    nume = -1
                    id.linkid = glinkid
                    id.linkarg = glinkarg
                ELSE
                    nume = VAL(elements$)
                END IF
            END IF

            id.arraytype = DOUBLETYPE
            IF cmemlist(idn + 1) THEN id.arraytype = id.arraytype + ISINCONVENTIONALMEMORY
            IF nume > 65536 THEN nume = nume - 65536: id.staticarray = 1

            id.arrayelements = nume
            id.callname = n$
        ELSE
            n$ = scope2$ + n$
            clearid
            id.t = DOUBLETYPE
            IF f = 1 THEN WriteBufLine defdatahandle, ct$ + " *" + n$ + "=NULL;"
            IF f = 1 THEN WriteBufLine DataTxtBuf, "if(" + n$ + "==NULL){"
            IF cmemlist(idn + 1) THEN
                id.t = id.t + ISINCONVENTIONALMEMORY
                IF f = 1 THEN WriteBufLine DataTxtBuf, "cmem_sp-=8;"
                IF f = 1 THEN WriteBufLine DataTxtBuf, n$ + "=(" + ct$ + "*)(dblock+cmem_sp);"
                IF f = 1 THEN WriteBufLine DataTxtBuf, "if (cmem_sp<qbs_cmem_sp) error(257);"
            ELSE
                IF f = 1 THEN WriteBufLine DataTxtBuf, n$ + "=(" + ct$ + "*)mem_static_malloc(8);"
            END IF
            IF f = 1 THEN WriteBufLine DataTxtBuf, "*" + n$ + "=0;"
            IF f = 1 THEN WriteBufLine DataTxtBuf, "}"
        END IF
        id.n = cvarname$
        IF method = 0 THEN
            id.mayhave = "#"
        END IF
        IF method = 1 THEN
            id.musthave = "#"
        END IF
        id.callname = n$
        regid
        vWatchVariable n$, 0
        IF Error_Happened THEN EXIT FUNCTION
        GOTO dim2exitfunc
    END IF

    IF typ$ = "_FLOAT" THEN
        ct$ = "long double"
        n$ = n$ + "FLOAT_" + varname$
        IF elements$ <> "" THEN
            arraydesc = 0
            cmps$ = varname$ + "##"
            IF f = 1 THEN
                try = findid(cmps$)
                IF Error_Happened THEN EXIT FUNCTION
                DO WHILE try
                    IF (id.arraytype) THEN
                        l$ = RTRIM$(id.cn)
                        arraydesc = currentid: scope2$ = scope$
                        EXIT DO
                    END IF
                    IF try = 2 THEN findanotherid = 1: try = findid(cmps$) ELSE try = 0
                    IF Error_Happened THEN EXIT FUNCTION
                LOOP
            END IF
            n$ = scope2$ + "ARRAY_" + n$

            'nume = allocarray(n$, elements$, 32)
            'IF arraydesc THEN goto dim2exitfunc
            'clearid

            IF f = 1 THEN

                IF LEN(elements$) = 1 AND ASC(elements$) = 63 THEN '"?"
                    E = arrayelementslist(idn + 1): IF E THEN elements$ = elements$ + _TOSTR$(E) 'eg. "?3" for a 3 dimensional array
                END IF
                nume = allocarray(n$, elements$, 32, 0)
                IF Error_Happened THEN EXIT FUNCTION
                l$ = l$ + sp + tlayout$
                IF arraydesc THEN GOTO dim2exitfunc
                clearid

            ELSE
                clearid
                IF elements$ = "?" THEN
                    nume = -1
                    id.linkid = glinkid
                    id.linkarg = glinkarg
                ELSE
                    nume = VAL(elements$)
                END IF
            END IF

            id.arraytype = FLOATTYPE
            IF cmemlist(idn + 1) THEN id.arraytype = id.arraytype + ISINCONVENTIONALMEMORY
            IF nume > 65536 THEN nume = nume - 65536: id.staticarray = 1

            id.arrayelements = nume
            id.callname = n$
        ELSE
            n$ = scope2$ + n$
            clearid
            id.t = FLOATTYPE
            IF f THEN WriteBufLine defdatahandle, ct$ + " *" + n$ + "=NULL;"
            IF f THEN WriteBufLine DataTxtBuf, "if(" + n$ + "==NULL){"
            IF cmemlist(idn + 1) THEN
                id.t = id.t + ISINCONVENTIONALMEMORY
                IF f THEN WriteBufLine DataTxtBuf, "cmem_sp-=32;"
                IF f THEN WriteBufLine DataTxtBuf, n$ + "=(" + ct$ + "*)(dblock+cmem_sp);"
                IF f THEN WriteBufLine DataTxtBuf, "if (cmem_sp<qbs_cmem_sp) error(257);"
            ELSE
                IF f THEN WriteBufLine DataTxtBuf, n$ + "=(" + ct$ + "*)mem_static_malloc(32);"
            END IF
            IF f THEN WriteBufLine DataTxtBuf, "*" + n$ + "=0;"
            IF f THEN WriteBufLine DataTxtBuf, "}"
        END IF
        id.n = cvarname$
        IF method = 0 THEN
            id.mayhave = "##"
        END IF
        IF method = 1 THEN
            id.musthave = "##"
        END IF
        id.callname = n$
        regid
        vWatchVariable n$, 0
        IF Error_Happened THEN EXIT FUNCTION
        GOTO dim2exitfunc
    END IF

    Give_Error "Unknown type": EXIT FUNCTION
    dim2exitfunc:

    IF dimsfarray THEN
        ids(idn).sfid = glinkid
        ids(idn).sfarg = glinkarg
    END IF

    'restore STATIC state
    IF dimstatic <> 0 AND dimshared = 0 THEN
        DataTxtBuf = OpenBuffer%("A", tmpdir$ + "data" + _TOSTR$(subfuncn) + ".txt")
        FreeTxtBuf = OpenBuffer%("A", tmpdir$ + "free" + _TOSTR$(subfuncn) + ".txt")
        defdatahandle = DataTxtBuf
    END IF

    tlayout$ = l$

END FUNCTION



' Return true when an expression is empty after stripping complete outer
' parenthesis pairs. This keeps ERASE () on the standard undefined-array error.

FUNCTION IsEmptyParenthesizedTarget% (expr$)
    n = numelements(expr$)
    IF n = 0 THEN IsEmptyParenthesizedTarget% = -1: EXIT FUNCTION

    DO WHILE n >= 2
        IF getelement$(expr$, 1) <> "(" OR getelement$(expr$, n) <> ")" THEN EXIT FUNCTION

        b = 0
        wrapped = -1
        FOR i = 1 TO n
            t$ = getelement$(expr$, i)
            IF t$ = "(" THEN b = b + 1
            IF t$ = ")" THEN
                b = b - 1
                IF b = 0 AND i <> n THEN wrapped = 0: EXIT FOR
            END IF
        NEXT
        IF wrapped = 0 OR b <> 0 THEN EXIT FUNCTION

        IF n = 2 THEN IsEmptyParenthesizedTarget% = -1: EXIT FUNCTION
        expr$ = getelements$(expr$, 2, n - 1)
        n = numelements(expr$)
        IF n = 0 THEN IsEmptyParenthesizedTarget% = -1: EXIT FUNCTION
    LOOP
END FUNCTION

FUNCTION IsWholeMemberArrayRef% (encoded$, source_type AS LONG)
    IF (source_type AND ISREFERENCE) = 0 THEN EXIT FUNCTION
    IF (source_type AND ISARRAY) = 0 THEN EXIT FUNCTION

    first_sep = INSTR(encoded$, sp3)
    IF first_sep = 0 THEN EXIT FUNCTION
    second_sep = INSTR(first_sep + LEN(sp3), encoded$, sp3)
    IF second_sep = 0 THEN EXIT FUNCTION
    third_sep = INSTR(second_sep + LEN(sp3), encoded$, sp3)
    IF third_sep = 0 THEN EXIT FUNCTION

    final_member_id = VAL(MID$(encoded$, second_sep + LEN(sp3), third_sep - second_sep - LEN(sp3)))
    IF final_member_id <= 0 THEN EXIT FUNCTION
    IF udtearrayelements(final_member_id) THEN IsWholeMemberArrayRef% = -1
END FUNCTION

FUNCTION HasFinalEmptyArrayBrackets% (expr$)
    DIM work AS STRING

    work = expr$
    token_count = numelements(work)
    IF token_count = 0 THEN EXIT FUNCTION

    ' Ignore balanced parentheses wrapping the complete argument.
    DO WHILE token_count >= 2
        IF getelement$(work, 1) <> "(" OR getelement$(work, token_count) <> ")" THEN EXIT DO

        nesting = 0
        whole_wrap = -1
        FOR token_index = 1 TO token_count
            token_text$ = getelement$(work, token_index)
            IF token_text$ = "(" THEN nesting = nesting + 1
            IF token_text$ = ")" THEN
                nesting = nesting - 1
                IF nesting = 0 AND token_index <> token_count THEN whole_wrap = 0: EXIT FOR
            END IF
        NEXT

        IF whole_wrap = 0 OR nesting <> 0 THEN EXIT DO
        work = getelements$(work, 2, token_count - 1)
        token_count = numelements(work)
        IF token_count = 0 THEN EXIT FUNCTION
    LOOP

    IF token_count < 2 THEN EXIT FUNCTION
    IF getelement$(work, token_count - 1) = "(" AND getelement$(work, token_count) = ")" THEN
        HasFinalEmptyArrayBrackets% = -1
    END IF
END FUNCTION

FUNCTION HasIndexedFinalMemberArray% (expr$)
    n = numelements(expr$)
    IF n = 0 THEN EXIT FUNCTION

    DO WHILE n >= 2
        IF getelement$(expr$, 1) <> "(" OR getelement$(expr$, n) <> ")" THEN EXIT DO

        b = 0
        wrapped = -1
        FOR i = 1 TO n
            t$ = getelement$(expr$, i)
            IF t$ = "(" THEN b = b + 1
            IF t$ = ")" THEN
                b = b - 1
                IF b = 0 AND i <> n THEN wrapped = 0: EXIT FOR
            END IF
        NEXT
        IF wrapped = 0 OR b <> 0 THEN EXIT DO

        expr$ = getelements$(expr$, 2, n - 1)
        n = numelements(expr$)
        IF n = 0 THEN EXIT FUNCTION
    LOOP

    IF getelement$(expr$, n) <> ")" THEN EXIT FUNCTION

    b = 1
    FOR i = n - 1 TO 1 STEP -1
        t$ = getelement$(expr$, i)
        IF t$ = ")" THEN b = b + 1
        IF t$ = "(" THEN
            b = b - 1
            IF b = 0 THEN
                IF i >= 3 THEN
                    ' Member(index) -> indexed final member array
                    ' Member()      -> whole-array request, not indexed
                    IF i < n - 1 THEN
                        IF getelement$(expr$, i - 2) = "." THEN HasIndexedFinalMemberArray% = -1
                    END IF
                END IF

                EXIT FUNCTION
            END IF
        END IF
    NEXT
END FUNCTION

FUNCTION FinalMemberArrayWholeExpr$ (expr AS STRING)
    DIM work AS STRING
    DIM leading_wraps AS STRING
    DIM trailing_wraps AS STRING
    DIM tok_count AS LONG
    DIM token_index AS LONG
    DIM depth AS LONG
    DIM wrapped AS LONG
    DIM token AS STRING
    DIM open_index AS LONG

    work = expr
    tok_count = numelements(work)
    IF tok_count = 0 THEN EXIT FUNCTION

    DO WHILE tok_count >= 2
        IF getelement$(work, 1) <> "(" OR getelement$(work, tok_count) <> ")" THEN EXIT DO

        depth = 0
        wrapped = -1
        FOR token_index = 1 TO tok_count
            token = getelement$(work, token_index)
            IF token = "(" THEN depth = depth + 1
            IF token = ")" THEN
                depth = depth - 1
                IF depth = 0 AND token_index <> tok_count THEN wrapped = 0: EXIT FOR
            END IF
        NEXT
        IF wrapped = 0 OR depth <> 0 THEN EXIT DO

        work = getelements$(work, 2, tok_count - 1)
        leading_wraps = leading_wraps + "("
        trailing_wraps = trailing_wraps + ")"
        tok_count = numelements(work)
        IF tok_count = 0 THEN EXIT FUNCTION
    LOOP

    IF getelement$(work, tok_count) <> ")" THEN EXIT FUNCTION

    depth = 1
    FOR token_index = tok_count - 1 TO 1 STEP -1
        token = getelement$(work, token_index)
        IF token = ")" THEN depth = depth + 1
        IF token = "(" THEN
            depth = depth - 1
            IF depth = 0 THEN
                open_index = token_index
                EXIT FOR
            END IF
        END IF
    NEXT

    IF open_index <= 0 THEN EXIT FUNCTION
    IF open_index >= tok_count - 1 THEN EXIT FUNCTION
    IF open_index < 3 THEN EXIT FUNCTION
    IF getelement$(work, open_index - 2) <> "." THEN EXIT FUNCTION

    FinalMemberArrayWholeExpr$ = leading_wraps + getelements$(work, 1, open_index) + ")" + trailing_wraps
END FUNCTION

FUNCTION udtreference$ (o$, a$, typ AS LONG)
    'UDT REFERENCE FORMAT
    'idno|udtno|udtelementno|byteoffset
    '     ^udt of the element, not of the id

    DIM dynlayout AS LONG
    DIM level_base_bits AS LONG
    DIM member_bytes AS LONG
    DIM member_offset_bytes AS LONG
    DIM desc_expr AS STRING
    DIM base_ptr AS STRING
    DIM root_base_ptr AS STRING
    DIM arr_index AS STRING
    DIM dyn_offset AS STRING
    DIM actual_member_dims AS LONG
    DIM matched_member_id AS LONG
    DIM udtElem AS LONG
    DIM guard_desc AS STRING
    DIM guard_udt AS LONG
    DIM guard_mode AS LONG

    obak$ = o$
    IF o$ = "" THEN o$ = "0" 'nested arrays

    'PRINT "called udtreference!"


    r$ = _TOSTR$(currentid) + sp3


    o = 0 'the fixed/known part of the offset

    dynlayout = 0
    IF id.dynudt THEN dynlayout = -1

    root_base_ptr = "((char*)" + scope$ + "UDT_" + RTRIM$(id.n) + ")"
    IF id.t = 0 THEN root_base_ptr = "((char*)" + scope$ + "ARRAY_UDT_" + RTRIM$(id.n) + "[0])"

    incmem = 0
    IF id.t THEN
        u = id.t AND UDTMASK
        IF id.t AND ISINCONVENTIONALMEMORY THEN incmem = 1
    ELSE
        u = id.arraytype AND UDTMASK
        IF id.arraytype AND ISINCONVENTIONALMEMORY THEN incmem = 1
    END IF
    udtElem = 0

    n = numelements(a$)
    IF n = 0 THEN GOTO fulludt

    i = 1
    udtfindelenext:
    level_base_bits = o
    IF getelement$(a$, i) <> "." THEN Give_Error "Expected .": EXIT FUNCTION
    i = i + 1
    n$ = UCASE$(getelement$(a$, i)) 'ucase must stay here
    nsym$ = removesymbol(n$): IF LEN(nsym$) THEN ntyp = typname2typ(nsym$): ntypsize = typname2typsize
    IF Error_Happened THEN EXIT FUNCTION

    IF n$ = "" THEN Give_Error "Expected .elementname": EXIT FUNCTION
    memberarrayend = 0
    IF i < n THEN
        IF getelement$(a$, i + 1) = "(" THEN
            b2 = 1
            memberarrayend = i + 2
            DO WHILE memberarrayend <= n
                l$ = getelement$(a$, memberarrayend)
                IF l$ = "(" THEN b2 = b2 + 1
                IF l$ = ")" THEN
                    b2 = b2 - 1
                    IF b2 = 0 THEN EXIT DO
                END IF
                memberarrayend = memberarrayend + 1
            LOOP
            IF b2 <> 0 THEN Give_Error "Expected )": EXIT FUNCTION
        END IF
    END IF
    udtfindele:
    IF udtElem = 0 THEN udtElem = udtxnext(u) ELSE udtElem = udtenext(udtElem)
    IF udtElem = 0 THEN Give_Error "Element not defined": EXIT FUNCTION

    ' Canonical descriptor layouts can contain alignment padding before descriptor slots
    ' or nested descriptor-owning UDTs. Use the precomputed member offset directly
    ' instead of reconstructing it by summing member sizes, which would silently
    ' discard that padding.
    IF dynlayout THEN o = level_base_bits + UDTDynMemberOffset&(udtElem)

    n2$ = RTRIM$(udtename(udtElem))

    IF n$ <> n2$ THEN
        IF dynlayout = 0 THEN o = o + udtesize(udtElem)
        GOTO udtfindele
    END IF

    matched_member_id = udtElem

    'check symbol after element's name (if given) is correct
    IF LEN(nsym$) THEN

        IF udtetype(udtElem) AND ISUDT THEN Give_Error "Invalid symbol after user defined type": EXIT FUNCTION
        IF ntyp <> udtetype(udtElem) OR ntypsize <> udtetypesize(udtElem) THEN
            IF nsym$ = "$" AND ((udtetype(udtElem) AND ISFIXEDLENGTH) <> 0) THEN GOTO correctsymbol
            Give_Error "Incorrect symbol after element name": EXIT FUNCTION
        END IF
    END IF
    correctsymbol:

    IF udtearrayelements(udtElem) THEN
        memberindexes$ = ""
        IF memberarrayend THEN memberindexes$ = getelements$(a$, i + 2, memberarrayend - 1)

        ' A TYPE member array normally requires an explicit element index. Some operations,
        ' however, must address the whole member array. When the caller enables
        ' udt_allow_bare_array, return a special reference carrying the parent id, member metadata
        ' id and physical member offset. Later stages use udtearrayfieldmode to interpret that
        ' offset as either an inline block (unmarked/_Static) or an explicit _Dynamic descriptor slot.
        IF memberarrayend = 0 OR memberindexes$ = "" THEN
            IF udt_allow_bare_array = 0 THEN Give_Error "Expected array index": EXIT FUNCTION
            IF memberarrayend THEN i = memberarrayend
            IF i <> n THEN Give_Error "Expected array index": EXIT FUNCTION

            r$ = r$ + _TOSTR$(u) + sp3 + _TOSTR$(udtElem) + sp3

            IF o MOD 8 THEN Give_Error "Non-byte aligned user defined type": EXIT FUNCTION
            o = o \ 8

            o$ = "(" + o$ + "+" + _TOSTR$(o) + ")" 'Inline block or explicit _Dynamic descriptor slot for the whole member array

            r$ = r$ + o$
            udtreference$ = r$
            typ = udtetype(udtElem) + ISREFERENCE + ISARRAY
            IF incmem THEN typ = typ + ISINCONVENTIONALMEMORY
            EXIT FUNCTION
        END IF

        IF dynlayout AND UDTMemberDynDesc%(udtElem) THEN
            IF o MOD 8 THEN Give_Error "Non-byte aligned user defined type": EXIT FUNCTION
            member_offset_bytes = o \ 8
            member_bytes = udt_dyn_array_elem_bytes(udtElem)

            base_ptr = root_base_ptr
            IF id.t = 0 AND CheckingOn THEN
                guard_desc = scope$ + "ARRAY_UDT_" + RTRIM$(id.n)
                guard_udt = id.arraytype AND UDTMASK
                guard_mode = id.dynudtmode
                IF guard_mode = 0 THEN guard_mode = id.dynudt
                base_ptr = "((char*)" + UDTRootDataGuard$(guard_desc, guard_udt, guard_mode) + ")"
                IF Error_Happened THEN EXIT FUNCTION
            END IF

            desc_expr = "(*((ptrszint**)(" + base_ptr + "+(" + o$ + "+" + _TOSTR$(member_offset_bytes) + "))))"
            actual_member_dims = DynMemberIndexDims%(memberindexes$)
            IF actual_member_dims <= 0 THEN Give_Error "Array index missing": EXIT FUNCTION
            desc_expr = UDTDynArrayDescGuard$(desc_expr, actual_member_dims)
            IF Error_Happened THEN EXIT FUNCTION
            arr_index = UDTDynArrayIndexExpr$(memberindexes$, actual_member_dims, desc_expr)
            IF Error_Happened THEN EXIT FUNCTION
            udtElem = matched_member_id
            dynmemlockexpr = "(mem_lock*)(" + desc_expr + "[" + desc_expr + "[3]*4+4])"
            dyn_offset = "((ptrszint)(((char*)" + desc_expr + "[0])+(" + arr_index + ")*" + _TOSTR$(member_bytes) + ")-(ptrszint)" + base_ptr + ")"
            o$ = dyn_offset
        ELSE
            arrindex$ = UDTArrayIndexExpr$(memberindexes$, udtearraydims(udtElem), udtearraydesc(udtElem))
            IF Error_Happened THEN EXIT FUNCTION
            udtElem = matched_member_id
            IF o MOD 8 THEN Give_Error "Non-byte aligned user defined type": EXIT FUNCTION
            IF dynlayout THEN
                arrbytes = UDTDynInlineElemBytes&(matched_member_id, id.dynudtmode)
            ELSE
                arrbytes = (udtesize(matched_member_id) \ 8) \ udtearrayelements(matched_member_id)
            END IF
            o = o \ 8

            o$ = "(" + o$ + "+" + _TOSTR$(o) + ")" 'Inline block for an indexed unmarked/_Static member array
            o$ = "(" + o$ + "+((" + arrindex$ + ")*" + _TOSTR$(arrbytes) + "))"
        END IF

        udtElem = matched_member_id
        o = 0
        i = memberarrayend
    ELSEIF memberarrayend THEN
        Give_Error "Element is not an array": EXIT FUNCTION
    END IF

    'Move into another UDT structure?
    IF i <> n THEN
        IF (udtetype(udtElem) AND ISUDT) = 0 THEN Give_Error "Expected user defined type": EXIT FUNCTION
        u = udtetype(udtElem) AND UDTMASK
        udtElem = 0
        i = i + 1
        GOTO udtfindelenext
    END IF

    'Change e reference to u | 0 reference?
    IF udtetype(udtElem) AND ISUDT THEN
        u = udtetype(udtElem) AND UDTMASK
        udtElem = 0
    END IF

    fulludt:

    r$ = r$ + _TOSTR$(u) + sp3 + _TOSTR$(udtElem) + sp3

    IF o MOD 8 THEN Give_Error "Non-byte aligned user defined type": EXIT FUNCTION
    o = o \ 8

    o$ = "(" + o$ + "+" + _TOSTR$(o) + ")" 'finish block

    r$ = r$ + o$

    udtreference$ = r$
    typ = udtetype(udtElem) + ISUDT + ISREFERENCE

    'full udt override:
    IF udtElem = 0 THEN
        typ = u + ISUDT + ISREFERENCE
    END IF

    IF obak$ <> "" THEN typ = typ + ISARRAY
    IF incmem THEN typ = typ + ISINCONVENTIONALMEMORY

    'print "UDTREF:"+r$+","+_TOSTR$(typ)

END FUNCTION

FUNCTION evaluate$ (a2$, typ AS LONG)
    DIM block(1000) AS STRING
    DIM evaledblock(1000) AS INTEGER
    DIM blocktype(1000) AS LONG
    'typ IS A RETURN VALUE
    '''DIM cli(15) AS INTEGER
    a$ = a2$
    typ = -1

    IF Debug THEN PRINT #9, "evaluating:[" + a2$ + "]"
    IF a2$ = "" THEN Give_Error "Syntax error": EXIT FUNCTION






    '''cl$ = classify(a$)

    blockn = 0
    n = numelements(a$)
    b = 0 'bracketting level
    FOR i = 1 TO n

        reevaluate:




        l$ = getelement(a$, i)


        IF Debug THEN PRINT #9, "#*#*#* reevaluating:" + l$, i


        IF i <> n THEN nextl$ = getelement(a$, i + 1) ELSE nextl$ = ""

        '''getclass cl$, i, cli()

        IF b = 0 THEN 'don't evaluate anything within brackets

            IF Debug THEN PRINT #9, l$

            l2$ = l$ 'pure version of l$
            FOR try_method = 1 TO 4
                l$ = l2$
                IF try_method = 2 OR try_method = 4 THEN
                    IF Error_Happened THEN EXIT FUNCTION
                    dtyp$ = removesymbol(l$): IF Error_Happened THEN dtyp$ = "": Error_Happened = 0
                    IF LEN(dtyp$) = 0 THEN
                        IF isoperator(l$) = 0 THEN
                            IF isvalidvariable(l$) THEN
                                IF LEFT$(l$, 1) = "_" THEN v = 27 ELSE v = ASC(UCASE$(l$)) - 64
                                l$ = l$ + defineextaz(v)
                            END IF
                        END IF
                    ELSE
                        l$ = l2$
                    END IF
                END IF
                try = findid(l$)
                IF Error_Happened THEN EXIT FUNCTION
                DO WHILE try

                    IF Debug THEN PRINT #9, try

                    'is l$ an array?
                    IF nextl$ = "(" THEN
                        IF id.arraytype THEN
                            IF (subfuncn = id.insubfuncn AND try_method <= 2) OR try_method >= 3 THEN
                                arrayid = currentid
                                constequation = 0
                                i2 = i + 2
                                b2 = 0
                                evalnextele3:
                                l2$ = getelement(a$, i2)
                                IF l2$ = "(" THEN b2 = b2 + 1
                                IF l2$ = ")" THEN
                                    b2 = b2 - 1
                                    IF b2 = -1 THEN
                                        arrayindexes$ = getelements$(a$, i + 2, i2 - 1)
                                        c$ = arrayreference(arrayindexes$, typ2)
                                        IF Error_Happened THEN EXIT FUNCTION
                                        i = i2

                                        'UDT
                                        IF typ2 AND ISUDT THEN
                                            ' A whole top-level UDT array reference, eg. X(), is valid only as
                                            ' a whole-array reference. It must not be silently reused as the
                                            ' parent object for a nested member access, eg. X().S(0), because
                                            ' that collapses the parent array offset to zero and effectively
                                            ' addresses the first element without an explicit index.
                                            IF arrayindexes$ = "" THEN
                                                IF i2 < n THEN
                                                    IF getelement$(a$, i2 + 1) = "." THEN Give_Error "Expected array index": EXIT FUNCTION
                                                END IF
                                            END IF

                                            'print "arrayref returned:"+c$
                                            getid arrayid
                                            IF Error_Happened THEN EXIT FUNCTION
                                            o$ = RIGHT$(c$, LEN(c$) - INSTR(c$, sp3))
                                            'change o$ to a byte offset
                                            u = typ2 AND UDTMASK
                                            s = udtxsize(u) \ 8
                                            IF id.dynudt THEN s = UDTDynLayoutSize&(u) \ 8
                                            o$ = "(" + o$ + ")*" + _TOSTR$(s)
                                            'print "calling evaludt with o$:"+o$
                                            GOTO evaludt
                                        END IF

                                        GOTO evalednextele3
                                    END IF
                                END IF
                                i2 = i2 + 1
                                GOTO evalnextele3
                                evalednextele3:
                                blockn = blockn + 1
                                block(blockn) = c$
                                evaledblock(blockn) = 2
                                blocktype(blockn) = typ2
                                IF (typ2 AND ISSTRING) THEN stringprocessinghappened = 1
                                GOTO evaled
                            END IF
                        END IF

                    ELSE
                        'not followed by "("

                        'is l$ a simple variable?
                        IF id.t <> 0 AND (id.t AND ISUDT) = 0 THEN
                            IF (subfuncn = id.insubfuncn AND try_method <= 2) OR try_method >= 3 THEN
                                constequation = 0
                                blockn = blockn + 1
                                makeidrefer block(blockn), blocktype(blockn)
                                IF (blocktype(blockn) AND ISSTRING) THEN stringprocessinghappened = 1
                                evaledblock(blockn) = 2
                                GOTO evaled
                            END IF
                        END IF

                        'is l$ a UDT?
                        IF id.t AND ISUDT THEN
                            IF (subfuncn = id.insubfuncn AND try_method <= 2) OR try_method >= 3 THEN
                                constequation = 0
                                o$ = ""
                                evaludt:
                                b2 = 0
                                i3 = i + 1
                                FOR i2 = i3 TO n
                                    e2$ = getelement(a$, i2)
                                    IF e2$ = "(" THEN b2 = b2 + 1
                                    IF b2 = 0 THEN
                                        IF e2$ = ")" OR isoperator(e2$) THEN
                                            i4 = i2 - 1
                                            GOTO gotudt
                                        END IF
                                    END IF
                                    IF e2$ = ")" THEN b2 = b2 - 1
                                NEXT
                                i4 = n
                                gotudt:
                                IF i4 < i3 THEN e$ = "" ELSE e$ = getelements$(a$, i3, i4)
                                'PRINT "UDTREFERENCE:";l$; e$
                                e$ = udtreference(o$, e$, typ2)
                                IF Error_Happened THEN EXIT FUNCTION
                                i = i4
                                blockn = blockn + 1
                                block(blockn) = e$
                                evaledblock(blockn) = 2
                                blocktype(blockn) = typ2
                                'is the following next necessary?
                                'IF (typ2 AND ISSTRING) THEN stringprocessinghappened = 1
                                GOTO evaled
                            END IF
                        END IF

                    END IF '"(" or no "("

                    'is l$ a function?
                    IF id.subfunc = 1 THEN
                        constequation = 0
                        IF getelement(a$, i + 1) = "(" THEN
                            i2 = i + 2
                            b2 = 0
                            args = 1
                            evalnextele:
                            l2$ = getelement(a$, i2)
                            IF l2$ = "(" THEN b2 = b2 + 1
                            IF l2$ = ")" THEN
                                b2 = b2 - 1
                                IF b2 = -1 THEN
                                    IF i2 = i + 2 THEN Give_Error "Expected (...)": EXIT FUNCTION
                                    c$ = evaluatefunc(getelements$(a$, i + 2, i2 - 1), args, typ2)
                                    IF Error_Happened THEN EXIT FUNCTION
                                    i = i2
                                    GOTO evalednextele
                                END IF
                            END IF
                            IF l2$ = "," AND b2 = 0 THEN args = args + 1
                            i2 = i2 + 1
                            GOTO evalnextele
                        ELSE
                            'no brackets
                            c$ = evaluatefunc("", 0, typ2)
                            IF Error_Happened THEN EXIT FUNCTION
                        END IF
                        evalednextele:
                        blockn = blockn + 1
                        block(blockn) = c$
                        evaledblock(blockn) = 2
                        blocktype(blockn) = typ2
                        IF (typ2 AND ISSTRING) THEN stringprocessinghappened = 1
                        GOTO evaled
                    END IF

                    IF try = 2 THEN findanotherid = 1: try = findid(l$) ELSE try = 0
                    IF Error_Happened THEN EXIT FUNCTION
                LOOP
            NEXT 'try method (1-4)

            'assume l$ an undefined array?

            IF i <> n THEN
                IF getelement$(a$, i + 1) = "(" THEN
                    IF isoperator(l$) = 0 THEN
                        IF isvalidvariable(l$) THEN
                            IF Debug THEN
                                PRINT #9, "**************"
                                PRINT #9, "about to auto-create array:" + l$, i
                                PRINT #9, "**************"
                            END IF
                            dtyp$ = removesymbol(l$)
                            IF Error_Happened THEN EXIT FUNCTION
                            'count the number of elements
                            nume = 1
                            b2 = 0
                            FOR i2 = i + 2 TO n
                                e$ = getelement(a$, i2)
                                IF e$ = "(" THEN b2 = b2 + 1
                                IF b2 = 0 AND e$ = "," THEN nume = nume + 1
                                IF e$ = ")" THEN b2 = b2 - 1
                                IF b2 = -1 THEN EXIT FOR
                            NEXT
                            fakee$ = "10": FOR i2 = 2 TO nume: fakee$ = fakee$ + sp + "," + sp + "10": NEXT
                            IF Debug THEN PRINT #9, "evaluate:creating undefined array using dim2(" + l$ + "," + dtyp$ + ",1," + fakee$ + ")"
                            autoIncForceUScore = 1
                            IF validname(l$) = 0 THEN Give_Error "Invalid array name": EXIT FUNCTION
                            IF GetRCStateVar(OptExpl) OR GetRCStateVar(OptExplArr) THEN Give_Error "Array '" + l$ + "' (" + symbol2fulltypename$(dtyp$) + ") not defined": EXIT FUNCTION
                            IF Error_Happened THEN EXIT FUNCTION
                            olddimstatic = dimstatic
                            method = 1
                            IF subfuncn THEN
                                autoarray = 1 'move dimensioning of auto array to data???.txt from inline
                                'static array declared by STATIC name()?
                                'check if varname is on the static list
                                xi = 1
                                FOR x = 1 TO staticarraylistn
                                    varname2$ = getelement$(staticarraylist, xi): xi = xi + 1
                                    typ2$ = getelement$(staticarraylist, xi): xi = xi + 1
                                    dimmethod2 = VAL(getelement$(staticarraylist, xi)): xi = xi + 1
                                    'check if they are similar
                                    IF UCASE$(l$) = UCASE$(varname2$) THEN
                                        l3$ = l2$: s$ = removesymbol(l3$)
                                        IF symbol2fulltypename$(dtyp$) = typ2$ OR (dimmethod2 = 0 AND s$ = "") THEN
                                            IF Error_Happened THEN EXIT FUNCTION
                                            'adopt properties
                                            l$ = varname2$
                                            dtyp$ = typ2$
                                            method = dimmethod2
                                            dimstatic = 3
                                        END IF 'typ
                                        IF Error_Happened THEN EXIT FUNCTION
                                    END IF 'varname
                                NEXT
                            END IF 'subfuncn
                            ignore = dim2(l$, dtyp$, method, fakee$)
                            IF Error_Happened THEN EXIT FUNCTION
                            dimstatic = olddimstatic
                            IF Debug THEN PRINT #9, "#*#*#* dim2 has returned!!!"
                            GOTO reevaluate
                        END IF
                    END IF
                END IF
            END IF

            l$ = l2$ 'restore l$

        END IF 'b=0

        IF l$ = "(" THEN
            IF b = 0 THEN i1 = i + 1
            b = b + 1
        END IF

        IF b = 0 THEN
            blockn = blockn + 1
            block(blockn) = l$
            evaledblock(blockn) = 0
        END IF

        IF l$ = ")" THEN
            b = b - 1
            IF b = 0 THEN
                c$ = evaluate(getelements$(a$, i1, i - 1), typ2)
                IF Error_Happened THEN EXIT FUNCTION
                IF (typ2 AND ISSTRING) THEN stringprocessinghappened = 1
                blockn = blockn + 1
                IF (typ2 AND ISPOINTER) THEN
                    block(blockn) = c$
                ELSE
                    block(blockn) = "(" + c$ + ")"
                END IF
                evaledblock(blockn) = 1
                blocktype(blockn) = typ2
            END IF
        END IF
        evaled:
    NEXT

    r$ = "" 'return value

    IF Debug THEN PRINT #9, "evaluated blocks:";
    FOR i = 1 TO blockn
        IF i <> blockn THEN
            IF Debug THEN PRINT #9, block(i) + CHR$(219);
        ELSE
            IF Debug THEN PRINT #9, block(i)
        END IF
    NEXT



    'identify any referenceable values
    FOR i = 1 TO blockn
        IF isoperator(block(i)) = 0 THEN
            IF evaledblock(i) = 0 THEN

                'a number?
                c = ASC(LEFT$(block(i), 1))
                IF c = 45 OR (c >= 48 AND c <= 57) THEN
                    num$ = block(i)
                    'a float?
                    f = 0
                    x = INSTR(num$, "E")
                    IF x THEN
                        f = 1: blocktype(i) = SINGLETYPE - ISPOINTER
                    ELSE
                        x = INSTR(num$, "D")
                        IF x THEN
                            f = 2: blocktype(i) = DOUBLETYPE - ISPOINTER
                        ELSE
                            x = INSTR(num$, "F")
                            IF x THEN
                                f = 3: blocktype(i) = FLOATTYPE - ISPOINTER
                            END IF
                        END IF
                    END IF
                    IF f THEN
                        'float
                        IF f = 2 OR f = 3 THEN MID$(num$, x, 1) = "E" 'D,F invalid in C++
                        IF f = 3 THEN num$ = num$ + "L" 'otherwise number is rounded to a double
                    ELSE
                        'integer
                        blocktype(i) = typname2typ(removesymbol$(num$))
                        IF Error_Happened THEN EXIT FUNCTION
                        IF blocktype(i) AND ISPOINTER THEN blocktype(i) = blocktype(i) - ISPOINTER
                        IF (blocktype(i) AND UDTMASK) > 32 THEN
                            IF blocktype(i) AND ISUNSIGNED THEN num$ = num$ + "ull" ELSE num$ = num$ + "ll"
                        END IF
                    END IF
                    block(i) = " " + num$ + " " 'pad with spaces to avoid C++ computation errors
                    evaledblock(i) = 1
                    GOTO evaledblock
                END IF

                'number?
                'fc = ASC(LEFT$(block(i), 1))
                'IF fc = 45 OR (fc >= 48 AND fc <= 57) THEN '- or 0-9
                ''it's a number
                ''check for an extension, if none, assume integer
                'blocktype(i) = INTEGER64TYPE - ISPOINTER
                'tblock$ = " " + block(i)
                'IF RIGHT$(tblock$, 2) = "##" THEN blocktype(i) = FLOATTYPE - ISPOINTER: block(i) = LEFT$(block(i), LEN(block$(i)) - 2): GOTO evfltnum
                'IF RIGHT$(tblock$, 1) = "#" THEN blocktype(i) = DOUBLETYPE - ISPOINTER: block(i) = LEFT$(block(i), LEN(block$(i)) - 1): GOTO evfltnum
                'IF RIGHT$(tblock$, 1) = "!" THEN blocktype(i) = SINGLETYPE - ISPOINTER: block(i) = LEFT$(block(i), LEN(block$(i)) - 1): GOTO evfltnum
                '
                ''C++ 32bit unsigned to signed 64bit
                'IF INSTR(block(i),".")=0 THEN
                '
                'negated=0
                'if left$(block(i),1)="-" then block(i)=right$(block(i),len(block(i))-1):negated=1
                '
                'if left$(block(i),2)="0x" then 'hex
                'if len(block(i))=10 then
                'if block(i)>="0x80000000" and block(i)<="0xFFFFFFFF" then block(i)="(int64)"+block(i): goto evnum
                'end if
                'if len(block(i))>10 then block(i)=block(i)+"ll": goto evnum
                'goto evnum
                'end if
                '
                'if left$(block(i),1)="0" then 'octal
                'if len(block(i))=12 then
                'if block(i)>="020000000000" and block(i)<="037777777777" then block(i)="(int64)"+block(i): goto evnum
                'if block(i)>"037777777777" then block(i)=block(i)+"ll": goto evnum
                'end if
                'if len(block(i))>12 then block(i)=block(i)+"ll": goto evnum
                'goto evnum
                'end if
                '
                ''decimal
                'if len(block(i))=10 then
                'if block(i)>="2147483648" and block(i)<="4294967295" then block(i)="(int64)"+block(i): goto evnum
                'if block(i)>"4294967295" then block(i)=block(i)+"ll": goto evnum
                'end if
                'if len(block(i))>10 then block(i)=block(i)+"ll"
                '
                'evnum:
                '
                'if negated=1 then block(i)="-"+block(i)
                '
                'END IF
                '
                'evfltnum:
                '
                'block(i) = " " + block(i)+" "
                'evaledblock(i) = 1
                'GOTO evaledblock
                'END IF

                'a typed string in ""
                IF LEFT$(block(i), 1) = CHR$(34) THEN
                    IF RIGHT$(block(i), 1) <> CHR$(34) THEN
                        block(i) = "qbs_new_txt_len(" + block(i) + ")"
                    ELSE
                        block(i) = "qbs_new_txt(" + block(i) + ")"
                    END IF
                    blocktype(i) = ISSTRING
                    evaledblock(i) = 1
                    stringprocessinghappened = 1
                    GOTO evaledblock
                END IF

                'create variable
                IF isvalidvariable(block(i)) THEN
                    x$ = block(i)

                    typ$ = removesymbol$(x$)
                    IF Error_Happened THEN EXIT FUNCTION

                    'add symbol extension if none given
                    IF LEN(typ$) = 0 THEN
                        IF LEFT$(x$, 1) = "_" THEN v = 27 ELSE v = ASC(UCASE$(x$)) - 64
                        typ$ = defineextaz(v)
                    END IF

                    'check that it hasn't just been created within this loop (a=b+b)
                    try = findid(x$ + typ$)
                    IF Error_Happened THEN EXIT FUNCTION
                    DO WHILE try
                        IF Debug THEN PRINT #9, try
                        IF id.t <> 0 AND (id.t AND ISUDT) = 0 THEN 'is x$ a simple variable?
                            GOTO simplevarfound
                        END IF
                        IF try = 2 THEN findanotherid = 1: try = findid(x$ + typ$) ELSE try = 0
                        IF Error_Happened THEN EXIT FUNCTION
                    LOOP

                    IF Debug THEN PRINT #9, "CREATING VARIABLE:" + x$
                    autoIncForceUScore = 1
                    IF validname(x$) = 0 THEN Give_Error "Invalid variable name": EXIT FUNCTION
                    IF GetRCStateVar(OptExpl) THEN Give_Error "Variable '" + x$ + "' (" + symbol2fulltypename$(typ$) + ") not defined": EXIT FUNCTION
                    retval = dim2(x$, typ$, 1, "")
                    manageVariableList "", vWatchNewVariable$, 0, 3
                    IF Error_Happened THEN EXIT FUNCTION

                    simplevarfound:
                    constequation = 0
                    makeidrefer block(i), blocktype(i)
                    IF (blocktype(i) AND ISSTRING) THEN stringprocessinghappened = 1
                    IF blockn = 1 THEN
                        IF (blocktype(i) AND ISREFERENCE) THEN GOTO returnpointer
                    END IF
                    'reference value
                    block(i) = refer(block(i), blocktype(i), 0): IF Error_Happened THEN EXIT FUNCTION
                    evaledblock(i) = 1
                    GOTO evaledblock
                END IF
                Give_Error "Invalid expression": EXIT FUNCTION

            ELSE
                IF (blocktype(i) AND ISREFERENCE) THEN
                    IF blockn = 1 THEN GOTO returnpointer

                    'if blocktype(i) and ISUDT then PRINT "UDT passed to refer by evaluate"

                    block(i) = refer(block(i), blocktype(i), 0)
                    IF Error_Happened THEN EXIT FUNCTION

                END IF

            END IF
        END IF
        evaledblock:
    NEXT


    'return a POINTER if possible
    IF blockn = 1 THEN
        IF evaledblock(1) THEN
            IF (blocktype(1) AND ISREFERENCE) THEN
                returnpointer:
                IF (blocktype(1) AND ISSTRING) THEN stringprocessinghappened = 1
                IF Debug THEN PRINT #9, "evaluated reference:" + block(1)
                typ = blocktype(1)
                evaluate$ = block(1)
                EXIT FUNCTION
            END IF
        END IF
    END IF
    'it cannot be returned as a pointer








    IF Debug THEN PRINT #9, "applying operators:";


    IF typ = -1 THEN
        typ = blocktype(1) 'init typ with first blocktype


        IF isoperator(block(1)) THEN 'but what if it starts with a UNARY operator?
            typ = blocktype(2) 'init typ with second blocktype
        END IF
    END IF

    nonop = 0
    FOR i = 1 TO blockn

        IF evaledblock(i) = 0 THEN
            isop = isoperator(block(i))
            IF isop THEN
                nonop = 0

                constequation = 0

                'operator found
                o$ = block(i)
                u = operatorusage(o$, typ, i$, lhstyp, rhstyp, result)

                IF u <> 5 AND u <> 6 THEN 'not unary
                    nonop = 1
                    IF i = 1 OR evaledblock(i - 1) = 0 THEN
                        IF i = 1 AND blockn = 1 AND o$ = "-" THEN Give_Error "Expected variable/value after '" + UCASE$(o$) + "'": EXIT FUNCTION 'guess - is neg in this case
                        Give_Error "Expected variable/value before '" + UCASE$(o$) + "'": EXIT FUNCTION
                    END IF
                END IF
                IF i = blockn OR evaledblock(i + 1) = 0 THEN Give_Error "Expected variable/value after '" + UCASE$(o$) + "'": EXIT FUNCTION

                'lhstyp & rhstyp bit-field values
                '1=integeral
                '2=floating point
                '4=string
                '8=bool *only used for result

                oldtyp = typ
                newtyp = blocktype(i + 1)

                'IF block(i - 1) = "6" THEN
                'PRINT o$
                'PRINT oldtyp AND ISFLOAT
                'PRINT blocktype(i - 1) AND ISFLOAT
                'END
                'END IF



                'numeric->string is illegal!
                IF (typ AND ISSTRING) = 0 AND (newtyp AND ISSTRING) <> 0 THEN
                    Give_Error "Cannot convert number to string": EXIT FUNCTION
                END IF

                'Offset protection: Override conversion rules for operator as necessary
                offsetmode = 0
                offsetcvi = 0
                IF (oldtyp AND ISOFFSET) <> 0 OR (newtyp AND ISOFFSET) <> 0 THEN
                    offsetmode = 2
                    IF newtyp AND ISOFFSET THEN
                        IF (newtyp AND ISUNSIGNED) = 0 THEN offsetmode = 1
                    END IF
                    IF oldtyp AND ISOFFSET THEN
                        IF (oldtyp AND ISUNSIGNED) = 0 THEN offsetmode = 1
                    END IF

                    'depending on the operate we may do things differently
                    'the default method is convert both sides to integer first
                    'but these operators are different: * / ^
                    IF o$ = "*" OR o$ = "/" OR o$ = "^" THEN
                        IF o$ = "*" OR o$ = "^" THEN
                            'for mult, if either side is a float cast integers to 'long double's first
                            IF (newtyp AND ISFLOAT) <> 0 OR (oldtyp AND ISFLOAT) <> 0 THEN
                                offsetcvi = 1
                                IF (oldtyp AND ISFLOAT) = 0 THEN lhstyp = 2
                                IF (newtyp AND ISFLOAT) = 0 THEN rhstyp = 2
                            END IF
                        END IF
                        IF o$ = "/" OR o$ = "^" THEN
                            'for division or exponentials, to prevent integer division cast integers to 'long double's
                            offsetcvi = 1
                            IF (oldtyp AND ISFLOAT) = 0 THEN lhstyp = 2
                            IF (newtyp AND ISFLOAT) = 0 THEN rhstyp = 2
                        END IF
                    ELSE
                        IF lhstyp AND 2 THEN lhstyp = 1 'force lhs and rhs to be integer values
                        IF rhstyp AND 2 THEN rhstyp = 1
                    END IF

                    IF result = 2 THEN result = 1 'force integer result
                    'note: result=1 just sets typ&=64 if typ is a float

                END IF

                'STEP 1: convert oldtyp and/or newtyp if required for the operator
                'convert lhs
                IF (oldtyp AND ISSTRING) THEN
                    IF (lhstyp AND 4) = 0 THEN Give_Error "Cannot convert string to number": EXIT FUNCTION
                ELSE
                    'oldtyp is numeric
                    IF lhstyp = 4 THEN Give_Error "Cannot convert number to string": EXIT FUNCTION
                    IF (oldtyp AND ISFLOAT) THEN
                        IF (lhstyp AND 2) = 0 THEN
                            'convert float to int
                            block(i - 1) = "qbr(" + block(i - 1) + ")"
                            oldtyp = 64&
                        END IF
                    ELSE
                        'oldtyp is an int
                        IF (lhstyp AND 1) = 0 THEN
                            'convert int to float
                            block(i - 1) = "((long double)(" + block(i - 1) + "))"
                            oldtyp = 256& + ISFLOAT
                        END IF
                    END IF
                END IF
                'convert rhs
                IF (newtyp AND ISSTRING) THEN
                    IF (rhstyp AND 4) = 0 THEN Give_Error "Cannot convert string to number": EXIT FUNCTION
                ELSE
                    'newtyp is numeric
                    IF rhstyp = 4 THEN Give_Error "Cannot convert number to string": EXIT FUNCTION
                    IF (newtyp AND ISFLOAT) THEN
                        IF (rhstyp AND 2) = 0 THEN
                            'convert float to int
                            block(i + 1) = "qbr(" + block(i + 1) + ")"
                            newtyp = 64&
                        END IF
                    ELSE
                        'newtyp is an int
                        IF (rhstyp AND 1) = 0 THEN
                            'convert int to float
                            block(i + 1) = "((long double)(" + block(i + 1) + "))"
                            newtyp = 256& + ISFLOAT
                        END IF
                    END IF
                END IF

                'Reduce floating point values to common base for comparison?
                IF isop = 10 THEN 'comparative (=) operator (check the value if isoperator() is changed!)
                    'Corrects problems encountered such as:
                    '    S = 2.1
                    '    IF S = 2.1 THEN PRINT "OK" ELSE PRINT "ERROR S PRINTS AS"; S; "BUT IS SEEN BY QB64 AS..."
                    '    IF S < 2.1 THEN PRINT "LESS THAN 2.1"
                    'concerns:
                    '1. Return value from TIMER will be reduced to a SINGLE in direct comparisons
                    'solution: assess, and only apply to SINGLE variables/arrays
                    '2. Comparison of a double higher/lower than single range may fail
                    'solution: out of range values convert to +/-1.#INF, making comparison still possible
                    IF (oldtyp AND ISFLOAT) <> 0 AND (newtyp AND ISFLOAT) <> 0 THEN 'both floating point
                        s1 = oldtyp AND UDTMASK: s2 = newtyp AND UDTMASK
                        IF s2 < s1 THEN s1 = s2
                        IF s1 = 32 THEN
                            block(i - 1) = "((float)(" + block(i - 1) + "))": oldtyp = 32& + ISFLOAT
                            block(i + 1) = "((float)(" + block(i + 1) + "))": newtyp = 32& + ISFLOAT
                        END IF
                        IF s1 = 64 THEN
                            block(i - 1) = "((double)(" + block(i - 1) + "))": oldtyp = 64& + ISFLOAT
                            block(i + 1) = "((double)(" + block(i + 1) + "))": newtyp = 64& + ISFLOAT
                        END IF
                    END IF 'both floating point
                END IF 'comparative operator

                typ = newtyp

                'STEP 2: markup typ
                '        if either side is a float, markup typ to largest float
                '        if either side is integer, markup typ
                'Note: A markup is a GUESS of what the return type will be,
                '      'result' can override this markup
                IF (oldtyp AND ISSTRING) = 0 AND (newtyp AND ISSTRING) = 0 THEN
                    IF (oldtyp AND ISFLOAT) <> 0 OR (newtyp AND ISFLOAT) <> 0 THEN
                        'float
                        b = 0: IF (oldtyp AND ISFLOAT) THEN b = oldtyp AND UDTMASK
                        IF (newtyp AND ISFLOAT) THEN
                            b2 = newtyp AND UDTMASK: IF b2 > b THEN b = b2
                        END IF
                        typ = ISFLOAT + b
                    ELSE
                        'integer
                        '***THIS IS THE IDEAL MARKUP FOR A 64-BIT SYSTEM***
                        'In reality 32-bit C++ only marks-up to 32-bit integers
                        b = oldtyp AND UDTMASK: b2 = newtyp AND UDTMASK: IF b2 > b THEN b = b2
                        typ = 64&
                        IF b = 64 THEN
                            IF (oldtyp AND ISUNSIGNED) <> 0 AND (newtyp AND ISUNSIGNED) <> 0 THEN typ = 64& + ISUNSIGNED
                        END IF
                    END IF
                END IF

                IF result = 1 THEN
                    IF (typ AND ISFLOAT) <> 0 OR (typ AND ISSTRING) <> 0 THEN typ = 64 'otherwise keep markuped integer type
                END IF
                IF result = 2 THEN
                    IF (typ AND ISFLOAT) = 0 THEN typ = ISFLOAT + 256
                END IF
                IF result = 4 THEN
                    typ = ISSTRING
                END IF
                IF result = 8 THEN 'bool
                    typ = 32
                END IF

                'Offset protection: Force result to be an offset type with correct signage
                IF offsetmode THEN
                    IF result <> 8 THEN 'boolean comparison results are allowed
                        typ = OFFSETTYPE - ISPOINTER: IF offsetmode = 2 THEN typ = typ + ISUNSIGNED
                    END IF
                END IF

                'override typ=ISFLOAT+256 to typ=ISFLOAT+64 for ^ operator's result
                IF u = 2 THEN
                    IF i$ = "pow2" THEN

                        IF offsetmode THEN Give_Error "Operator '^' cannot be used with an _OFFSET": EXIT FUNCTION

                        'QB-like conversion of math functions returning floating point values
                        'reassess oldtype & newtype
                        b = oldtyp AND UDTMASK
                        IF oldtyp AND ISFLOAT THEN
                            'no change to b
                        ELSE
                            IF b > 16 THEN b = 64 'larger than INTEGER? return DOUBLE
                            IF b > 32 THEN b = 256 'larger than LONG? return _FLOAT
                            IF b <= 16 THEN b = 32
                        END IF
                        b2 = newtyp AND UDTMASK
                        IF newtyp AND ISFLOAT THEN
                            IF b2 > b THEN b = b2
                        ELSE
                            b3 = 32
                            IF b2 > 16 THEN b3 = 64 'larger than INTEGER? return DOUBLE
                            IF b2 > 32 THEN b3 = 256 'larger than LONG? return _FLOAT
                            IF b3 > b THEN b = b3
                        END IF
                        typ = ISFLOAT + b

                    END IF 'pow2
                END IF 'u=2

                'STEP 3: apply operator appropriately

                IF u = 6 THEN
                    block(i + 1) = "-(" + i$ + "(" + block(i + 1) + ")" + ")"
                    block(i) = "": i = i + 1: GOTO operatorapplied
                END IF

                IF u = 5 THEN
                    block(i + 1) = i$ + "(" + block(i + 1) + ")"
                    block(i) = "": i = i + 1: GOTO operatorapplied
                END IF

                'binary operators

                IF u = 1 THEN
                    block(i + 1) = block(i - 1) + i$ + block(i + 1)
                    block(i - 1) = "": block(i) = "": i = i + 1: GOTO operatorapplied
                END IF

                IF u = 2 THEN
                    block(i + 1) = i$ + "(" + block(i - 1) + "," + block(i + 1) + ")"
                    block(i - 1) = "": block(i) = "": i = i + 1: GOTO operatorapplied
                END IF

                IF u = 3 THEN
                    block(i + 1) = "-(" + block(i - 1) + i$ + block(i + 1) + ")"
                    block(i - 1) = "": block(i) = "": i = i + 1: GOTO operatorapplied
                END IF

                IF u = 4 THEN
                    block(i + 1) = "~" + block(i - 1) + i$ + block(i + 1)
                    block(i - 1) = "": block(i) = "": i = i + 1: GOTO operatorapplied
                END IF

                '...more?...

                Give_Error "ERROR: Operator could not be applied correctly!": EXIT FUNCTION '<--should never happen!
                operatorapplied:

                IF offsetcvi THEN block(i) = "qbr(" + block(i) + ")": offsetcvi = 0
                offsetmode = 0

            ELSE
                nonop = nonop + 1
            END IF
        ELSE
            nonop = nonop + 1
        END IF
        IF nonop > 1 THEN Give_Error "Expected operator in equation": EXIT FUNCTION
    NEXT
    IF Debug THEN PRINT #9, ""

    'join blocks
    FOR i = 1 TO blockn
        r$ = r$ + block(i)
    NEXT

    IF Debug THEN
        PRINT #9, "evaluated:" + r$ + " AS TYPE:";
        IF (typ AND ISSTRING) THEN PRINT #9, "[ISSTRING]";
        IF (typ AND ISFLOAT) THEN PRINT #9, "[ISFLOAT]";
        IF (typ AND ISUNSIGNED) THEN PRINT #9, "[ISUNSIGNED]";
        IF (typ AND ISPOINTER) THEN PRINT #9, "[ISPOINTER]";
        IF (typ AND ISFIXEDLENGTH) THEN PRINT #9, "[ISFIXEDLENGTH]";
        IF (typ AND ISINCONVENTIONALMEMORY) THEN PRINT #9, "[ISINCONVENTIONALMEMORY]";
        PRINT #9, "(size in bits=" + _TOSTR$(typ AND UDTMASK) + ")"
    END IF


    evaluate$ = r$



END FUNCTION




FUNCTION evaluatefunc$ (a2$, args AS LONG, typ AS LONG)
    a$ = a2$

    DIM member_element_id AS LONG 'metadata index of the currently resolved TYPE member array
    DIM ulboundarray AS STRING
    DIM ulboundarraytyp AS LONG
    DIM ulboundarrayisnested AS INTEGER
    DIM ulboundarrayisdyn AS INTEGER
    DIM ulboundid AS LONG
    DIM ulboundoffset AS STRING
    DIM ulboundbase AS STRING
    DIM ulbounddesc AS STRING


    IF Debug THEN PRINT #9, "evaluatingfunction:" + RTRIM$(id.n) + ":" + a$

    DIM id2 AS idstruct

    id2 = id
    n$ = RTRIM$(id2.n)
    typ = id2.ret
    targetid = currentid

    IF RTRIM$(id2.callname) = "func_stub" THEN Give_Error "Command not implemented": EXIT FUNCTION
    IF RTRIM$(id2.callname) = "func_input" AND args = 1 AND inputfunctioncalled = 0 THEN
        inputfunctioncalled = -1
        IF GetRCStateVar(vWatchOn) THEN
            WriteBufLine MainTxtBuf, "*__LONG_VWATCH_LINENUMBER= -4; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars);"
        END IF
    END IF

    SetDependency id2.Dependency

    argCount = countFunctionElements(a$)
    REDIM providedArgs(argCount)

    passomit = 0
    hasOptionalFirstArg = 0
    firstOptionalArgument = 0

    f$ = RTRIM$(id2.specialformat)
    IF LEN(f$) THEN 'special format given

        FOR fi = 1 TO argCount
            providedArgs(fi) = hasFunctionElement(a$, fi)
        NEXT

        ' Special case for the INSTR and _INSTRREV format, which have an optional argument at the beginning
        IF f$ = "[?],?,?" THEN
            hasOptionalFirstArg = -1

            IF UBOUND(providedArgs) = 2 THEN
                REDIM _PRESERVE providedArgs(3)

                providedArgs(3) = providedArgs(2)
                providedArgs(2) = providedArgs(1)
                providedArgs(1) = 0 ' The first argument was not provided

                skipFirstArg = -1
            END IF
        END IF

        IF NOT isValidArgSet(id2.specialformat, providedArgs(), firstOptionalArgument) THEN
            IF LEN(id2.hr_syntax) > 0 THEN
                Give_Error "Incorrect number of arguments - Reference: " + id2.hr_syntax
            ELSE
                Give_Error "Incorrect number of arguments passed to function"
            END IF
            EXIT FUNCTION
        END IF

        passomit = 1 'pass omit flags param to function

    ELSE 'no special format given

        FOR fi = 1 TO argCount
            providedArgs(fi) = -1
        NEXT

        IF n$ = "ASC" AND args = 2 THEN GOTO skipargnumchk
        IF id2.overloaded = -1 AND (args >= id2.minargs AND args <= id2.args) THEN GOTO skipargnumchk

        IF id2.args <> args THEN
            IF LEN(id2.hr_syntax) > 0 THEN
                Give_Error "Incorrect number of arguments - Reference: " + id2.hr_syntax
            ELSE
                Give_Error "Incorrect number of arguments passed to function"
            END IF
            EXIT FUNCTION
        END IF

    END IF

    skipargnumchk:

    r$ = RTRIM$(id2.callname) + "("
    funcargprep$ = ""


    IF id2.args <> 0 THEN

        curarg = 1
        firsti = 1

        ' The first optional argument is missing and not included in the
        ' argument list
        IF skipFirstArg THEN
            r$ = r$ + "NULL,"
            curarg = 2
        END IF

        n = numelements(a$)

        FOR i = 1 TO n
            l$ = getelement(a$, i)
            IF l$ = "(" THEN b = b + 1
            IF l$ = ")" THEN b = b - 1
            IF (l$ = "," AND b = 0) OR (i = n) THEN
                IF NOT providedArgs(curarg) THEN
                    IF i = n THEN Give_Error "Last function argument cannot be empty": EXIT FUNCTION

                    r$ = r$ + "NULL,"
                    firsti = i + 1
                    curarg = curarg + 1
                    _CONTINUE
                END IF

                targettyp = CVL(MID$(id2.arg, curarg * 4 - 4 + 1, 4))
                nele = ASC(MID$(id2.nele, curarg, 1))
                nelereq = ASC(MID$(id2.nelereq, curarg, 1))

                IF i = n THEN
                    e$ = getelements$(a$, firsti, i)
                ELSE
                    e$ = getelements$(a$, firsti, i - 1)
                END IF

                IF LEFT$(e$, 2) = "(" + sp THEN dereference = 1 ELSE dereference = 0


                ' VAL support
                IF n$ = "VAL" THEN
                    IF curarg = 2 THEN ' data type
                        valReturnType$ = type2symbol$(e$)
                        IF Error_Happened THEN EXIT FUNCTION

                        SELECT CASE valReturnType$
                            CASE "%%", "%", "&", "&&", "%&"
                                typ& = INTEGER64TYPE - ISPOINTER
                                r$ = "qbs_val<int64_t>" + r$

                            CASE "~%%", "~%", "~&", "~&&", "~%&"
                                typ& = UINTEGER64TYPE - ISPOINTER
                                r$ = "qbs_val<uint64_t>" + r$

                            CASE "!", "#", "##"
                                typ& = FLOATTYPE - ISPOINTER
                                r$ = "qbs_val<long double>" + r$

                            CASE ELSE
                                Give_Error "VAL TYPE unsupported"
                                EXIT FUNCTION
                        END SELECT

                        r$ = r$ + ")"
                        noComma = 0

                        GOTO evalfuncspecial ' wrap up early to avoid adding junk at the end of the call
                    END IF
                END IF

                ' CAST support
                IF n$ = "_CAST" THEN
                    IF curarg = 1 THEN ' data type
                        castType$ = type2symbol$(e$)
                        IF Error_Happened THEN EXIT FUNCTION

                        SELECT CASE castType$
                            CASE "%%", "~%%", "%", "~%", "&", "~&", "&&", "~&&", "%&", "~%&", "!", "#", "##"
                                typ& = typname2typ(castType$) - ISPOINTER
                                IF Error_Happened THEN EXIT FUNCTION

                                r$ = r$ + "(" + typ2ctyp(typ&, castType$) + ")" ' both args are not really needed. Oh well!
                                IF Error_Happened THEN EXIT FUNCTION

                            CASE ELSE
                                Give_Error "_CAST TYPE unsupported"
                                EXIT FUNCTION
                        END SELECT

                        e$ = ""
                        noComma = 1

                        GOTO dontevaluate
                    END IF
                END IF

                '*special case CVI,CVL,CVS,CVD,_CV (part #1)
                IF n$ = "_CV" THEN
                    IF curarg = 1 THEN
                        cvtype$ = type2symbol$(e$)
                        IF Error_Happened THEN EXIT FUNCTION
                        e$ = ""
                        GOTO dontevaluate
                    END IF
                END IF

                '*special case MKI,MKL,MKS,MKD,_MK (part #1)

                IF n$ = "_MK" THEN
                    IF RTRIM$(id2.musthave) = "$" THEN
                        IF curarg = 1 THEN
                            mktype$ = type2symbol$(e$)
                            IF Error_Happened THEN EXIT FUNCTION
                            IF Debug THEN PRINT #9, "_MK:[" + e$ + "]:[" + mktype$ + "]"
                            e$ = ""
                            GOTO dontevaluate
                        END IF
                    END IF
                END IF

                IF n$ = "_EMBEDDED" THEN
                    IF RTRIM$(id2.musthave) = "$" THEN
                        IF curarg = 1 THEN
                            'check handle argument
                            EmbedHandle$ = e$
                            rse$ = "Embed-Handle must be a single literal string in quotes, not a variable"
                            IF INSTR(EmbedHandle$, CHR$(13)) > 0 THEN Give_Error rse$: EXIT FUNCTION
                            bra = INSTR(EmbedHandle$, CHR$(34)): ket = INSTR(bra + 1, EmbedHandle$, CHR$(34))
                            IF bra = 0 OR ket = 0 THEN Give_Error rse$: EXIT FUNCTION
                            EmbedHandle$ = MID$(EmbedHandle$, bra + 1, ket - bra - 1)
                            rse$ = "Embed-Handle cannot be an empty string"
                            IF LEN(EmbedHandle$) = 0 THEN Give_Error rse$: EXIT FUNCTION
                            'verify handle validity (Aa-Zz/0-9, begin with letter)
                            SELECT CASE ASC(EmbedHandle$, 1)
                                CASE 0 TO 64, 91 TO 96, 123 TO 255
                                    rse$ = "First char of Embed-Handle '" + EmbedHandle$ + "' must be a letter"
                                    Give_Error rse$: EXIT FUNCTION
                            END SELECT
                            FOR rsi = 2 TO LEN(EmbedHandle$)
                                SELECT CASE ASC(EmbedHandle$, rsi)
                                    CASE 0 TO 47, 58 TO 64, 91 TO 96, 123 TO 255
                                        rse$ = "Embed-Handle '" + EmbedHandle$ + "' has invalid chars, use Aa-Zz/0-9 only"
                                        Give_Error rse$: EXIT FUNCTION
                                END SELECT
                            NEXT rsi
                            'check if a respective file + handle was embedded
                            eflUB = UBOUND(embedFileList$, 2)
                            FOR rsi = 0 TO eflUB
                                IF embedFileList$(eflHand, rsi) = EmbedHandle$ THEN EXIT FOR
                            NEXT rsi
                            IF rsi > eflUB THEN
                                rse$ = "Embed-Handle '" + EmbedHandle$ + "' is undefined (check your $EMBED lines)"
                                Give_Error rse$: EXIT FUNCTION
                            ELSE
                                embedFileList$(eflUsed, rsi) = "yes" 'mark respective handle as used
                            END IF
                        END IF
                    END IF
                END IF

                IF n$ = "UBOUND" OR n$ = "LBOUND" THEN

                    IF curarg = 1 THEN
                        original_e$ = e$
                        ulboundarrayisnested = 0
                        ulboundarrayisdyn = 0

                        IF HasIndexedFinalMemberArray%(original_e$) THEN
                            Give_Error "Incorrect number of arguments": EXIT FUNCTION
                        END IF

                        ' Only expressions containing a member dereference can use the bare
                        ' TYPE member-array path.
                        '
                        ' Examples:
                        '   UBOUND(P(0).grid, 2)      -> member-array path
                        '   UBOUND(usedVariableList)  -> ordinary-array path
                        '   UBOUND(DEPENDENCY)        -> ordinary-array path
                        '
                        ' Important:
                        ' The first-stage decision must be based on the source-form expression and on
                        ' whether it evaluates to an array reference at all. Do NOT require the encoded
                        ' internal sp3 layout here, because a failure in that extra check would wrongly
                        ' fall back to the ordinary array() path and turn:
                        '   Items(0).Grid
                        ' into:
                        '   Items(0).Grid()
                        ' which then raises "Expected array index".
                        IF INSTR(original_e$, ".") THEN
                            udt_allow_bare_array = -1
                            e$ = evaluate(original_e$, sourcetyp)
                            udt_allow_bare_array = 0

                            IF Error_Happened = 0 THEN
                                IF ((sourcetyp AND ISREFERENCE) <> 0) AND ((sourcetyp AND ISARRAY) <> 0) THEN
                                    ulboundarrayisnested = -1
                                END IF
                            END IF
                        END IF

                        ' Every non-member-array case must continue through the ordinary array()
                        ' fallback path. That includes ordinary arrays and arrays of TYPE.
                        IF Error_Happened OR ulboundarrayisnested = 0 THEN
                            Error_Happened = 0
                            e$ = original_e$ + sp + "(" + sp + ")"
                            e$ = evaluate(e$, sourcetyp)
                            IF Error_Happened THEN EXIT FUNCTION
                            ulboundarrayisnested = 0
                        END IF

                        IF (sourcetyp AND ISREFERENCE) = 0 THEN Give_Error "Expected array-name": EXIT FUNCTION
                        IF (sourcetyp AND ISARRAY) = 0 THEN Give_Error "Expected array-name": EXIT FUNCTION
                        'make a note of the array's index for later
                        ulboundarray$ = e$
                        ulboundarraytyp = sourcetyp
                        e$ = ""
                        r$ = ""
                        GOTO dontevaluate
                    END IF
                END IF


                '*special case: INPUT$ function
                IF n$ = "INPUT" THEN
                    IF RTRIM$(id2.musthave) = "$" THEN
                        IF curarg = 2 THEN
                            IF LEFT$(e$, 2) = "#" + sp THEN e$ = RIGHT$(e$, LEN(e$) - 2)
                        END IF
                    END IF
                END IF


                '*special case*
                IF n$ = "ASC" THEN
                    IF curarg = 2 THEN
                        e$ = evaluatetotyp$(e$, 32&)
                        IF Error_Happened THEN EXIT FUNCTION
                        typ& = LONGTYPE - ISPOINTER
                        r$ = r$ + e$ + ")"
                        GOTO evalfuncspecial
                    END IF
                END IF


                'WriteBufLine MainTxtBuf, "n$="; n$
                'WriteBufLine MainTxtBuf, "curarg="; curarg
                'WriteBufLine MainTxtBuf, "e$="; e$
                'WriteBufLine MainTxtBuf, "r$="; r$

                '*special case*
                IF n$ = "_MEMGET" THEN
                    IF curarg = 1 THEN
                        memget_blk$ = e$
                    END IF
                    IF curarg = 2 THEN
                        memget_offs$ = e$
                    END IF
                    IF curarg = 3 THEN
                        e$ = UCASE$(e$)
                        IF INSTR(e$, sp + "*" + sp) THEN 'multiplier will have an appended %,& or && symbol
                            IF RIGHT$(e$, 2) = "&&" THEN
                                e$ = LEFT$(e$, LEN(e$) - 2)
                            ELSE
                                IF RIGHT$(e$, 1) = "&" OR RIGHT$(e$, 1) = "%" THEN e$ = LEFT$(e$, LEN(e$) - 1)
                            END IF
                        END IF
                        t = typname2typ(e$)
                        IF t = 0 THEN Give_Error "Invalid TYPE name": EXIT FUNCTION
                        IF t AND ISOFFSETINBITS THEN Give_Error "_BIT TYPE unsupported": EXIT FUNCTION
                        memget_size = typname2typsize
                        IF t AND ISSTRING THEN
                            IF (t AND ISFIXEDLENGTH) = 0 THEN Give_Error "Expected STRING * ...": EXIT FUNCTION
                            memget_ctyp$ = "qbs*"
                        ELSE
                            IF t AND ISUDT THEN
                                memget_size = udtxsize(t AND UDTMASK) \ 8
                                memget_ctyp$ = "void*"
                            ELSE
                                memget_size = (t AND UDTMASK) \ 8
                                memget_ctyp$ = typ2ctyp$(t, "")
                            END IF
                        END IF





                        'assume checking off
                        offs$ = evaluatetotyp(memget_offs$, OFFSETTYPE - ISPOINTER)
                        blkoffs$ = evaluatetotyp(memget_blk$, -6)
                        IF CheckingOn THEN
                            'change offs$ to be the return of the safe version
                            offs$ = "func__memget((mem_block*)" + blkoffs$ + "," + offs$ + "," + _TOSTR$(memget_size) + ")"
                        END IF
                        IF t AND ISSTRING THEN
                            r$ = "qbs_new_txt_len((char*)" + offs$ + "," + _TOSTR$(memget_size) + ")"
                        ELSE
                            IF t AND ISUDT THEN
                                r$ = "((void*)+" + offs$ + ")"
                                t = ISUDT + ISPOINTER + (t AND UDTMASK)
                            ELSE
                                r$ = "*(" + memget_ctyp$ + "*)(" + offs$ + ")"
                                IF t AND ISPOINTER THEN t = t - ISPOINTER
                            END IF
                        END IF







                        typ& = t


                        GOTO evalfuncspecial
                    END IF
                END IF

                '------------------------------------------------------------------------------------------------------------
                e2$ = e$

                allow_bare_member_array = 0
                member_array_arg_source$ = ""
                ' These contexts may address a whole TYPE member array; later stages distinguish
                ' inline storage (unmarked/_Static) from an explicit _Dynamic descriptor. Everywhere
                ' else the parser must continue to require an explicit element index.
                IF n$ = "_OFFSET" THEN allow_bare_member_array = -1
                IF n$ = "_MEM" AND curarg = 1 AND args = 1 THEN allow_bare_member_array = -1
                IF n$ = "LEN" AND curarg = 1 AND args = 1 THEN allow_bare_member_array = -1
                'Negative targettyp values are internal sentinel types (for example -1
                'means "any numeric argument" for ABS). Do not interpret their set bits as
                'real type flags such as ISARRAY.
                IF targettyp >= 0 THEN
                    IF targettyp AND ISARRAY THEN
                        allow_bare_member_array = -1
                        member_array_arg_source$ = e2$
                    END IF
                END IF

                IF allow_bare_member_array THEN udt_allow_bare_array = -1
                e$ = evaluate(e$, sourcetyp)
                IF allow_bare_member_array THEN udt_allow_bare_array = 0
                IF Error_Happened THEN EXIT FUNCTION

                ' Check the original spelling only when the encoded UDT reference identifies
                ' the final member itself as an array.  ISARRAY alone is insufficient because
                ' a scalar field of a parent UDT array also carries that flag.
                IF member_array_arg_source$ <> "" THEN
                    IF INSTR(member_array_arg_source$, ".") THEN
                        IF IsWholeMemberArrayRef%(e$, sourcetyp) THEN
                            IF HasFinalEmptyArrayBrackets%(member_array_arg_source$) = 0 THEN Give_Error "Expected: Array Name()": EXIT FUNCTION
                        END IF
                    END IF
                END IF
                '------------------------------------------------------------------------------------------------------------

                ' VAL support
                IF n$ = "VAL" THEN
                    IF curarg = 1 THEN
                        IF args = 1 THEN ' fallback to long double if no type (second argument) is specified
                            IF NOT Type_IsString(sourcetyp) _ORELSE Type_IsUDTContainer(sourcetyp) THEN
                                Give_Error "Expected STRING argument"
                                EXIT FUNCTION
                            END IF

                            IF (sourcetyp AND ISREFERENCE) THEN e$ = refer(e$, sourcetyp, 0)
                            IF Error_Happened THEN EXIT FUNCTION

                            typ& = FLOATTYPE - ISPOINTER ' default to earlier QB64 behavior
                            r$ = "qbs_val<long double>" + r$ + e$ + ")"

                            GOTO evalfuncspecial ' wrap up early to avoid adding junk at the end of the call
                        ELSE
                            ' If we have more than 1 arg then we'll let the existing logic validate and handle arg 1
                            noComma = 1 ' avoid adding a comma at the end
                        END IF
                    END IF
                END IF

                ' CAST support
                IF n$ = "_CAST" THEN
                    IF curarg = 2 THEN ' numeric value
                        noComma = 0

                        IF NOT Type_IsArithmetic(sourcetyp) _ORELSE Type_IsUDTContainer(sourcetyp) THEN
                            Give_Error "Expected numeric argument"
                            EXIT FUNCTION
                        END IF

                        IF sourcetyp AND ISREFERENCE THEN e$ = refer(e$, sourcetyp, 0)
                        IF Error_Happened THEN EXIT FUNCTION

                        r$ = r$ + "(" + e$ + "))"

                        GOTO evalfuncspecial
                    END IF
                END IF

                ' IIF support
                IF n$ = "_IIF" THEN
                    IF curarg = 1 THEN ' expression
                        r$ = r$ + "("
                        noComma = 1
                    ELSEIF curarg = 2 THEN ' true part
                        IF sourcetyp AND ISREFERENCE THEN e$ = refer(e$, sourcetyp, 0)
                        IF Error_Happened THEN EXIT FUNCTION

                        arg2Typ& = sourcetyp ' save the type of the 2nd argument

                        r$ = r$ + ")?(" + e$ + "):"
                        e$ = _STR_EMPTY
                        noComma = 1

                        GOTO dontevaluate
                    ELSEIF curarg = 3 THEN ' false part
                        noComma = 0

                        IF Type_IsString(sourcetyp) <> Type_IsString(arg2Typ&) THEN
                            Give_Error "falsePart and truePart must be of the same type"
                            EXIT FUNCTION
                        END IF

                        IF sourcetyp AND ISREFERENCE THEN e$ = refer(e$, sourcetyp, 0)
                        IF Error_Happened THEN EXIT FUNCTION

                        typ& = _IIF(Type_IsString(arg2Typ&), arg2Typ&, Type_PromoteArithmeticType(arg2Typ&, sourcetyp))
                        r$ = r$ + "(" + e$ + "))"

                        GOTO evalfuncspecial
                    END IF
                END IF

                ' _MIN & _MAX support
                IF n$ = "_MIN" _ORELSE n$ = "_MAX" THEN
                    minmax_n$ = LCASE$(RIGHT$(n$, 3))

                    IF curarg = 1 THEN
                        IF NOT Type_IsArithmetic(sourcetyp) _ORELSE Type_IsUDTContainer(sourcetyp) THEN
                            Give_Error "Expected numeric argument"
                            EXIT FUNCTION
                        END IF

                        IF sourcetyp AND ISREFERENCE THEN e$ = refer(e$, sourcetyp, 0)
                        IF Error_Happened THEN EXIT FUNCTION

                        arg1Typ& = sourcetyp ' save the type of the 1st argument
                        r$ = e$ ' save the partitially generated C code
                        e$ = _STR_EMPTY

                        GOTO dontevaluate
                    ELSEIF curarg = 2 THEN
                        IF NOT Type_IsArithmetic(sourcetyp) _ORELSE Type_IsUDTContainer(sourcetyp) THEN
                            Give_Error "Expected numeric argument"
                            EXIT FUNCTION
                        END IF

                        IF sourcetyp AND ISREFERENCE THEN e$ = refer(e$, sourcetyp, 0)
                        IF Error_Happened THEN EXIT FUNCTION

                        typ& = Type_PromoteArithmeticType(arg1Typ&, sourcetyp)
                        r$ = "std::" + minmax_n$ + "<" + Type_GetCppArithmeticType(typ&) + ">(" + r$ + e$ + ")"
                        IF Error_Happened THEN EXIT FUNCTION

                        GOTO evalfuncspecial
                    END IF
                END IF

                ' _CLAMP support
                IF n$ = "_CLAMP" THEN
                    IF curarg = 1 THEN
                        IF NOT Type_IsArithmetic(sourcetyp) _ORELSE Type_IsUDTContainer(sourcetyp) THEN
                            Give_Error "Expected numeric argument"
                            EXIT FUNCTION
                        END IF

                        IF sourcetyp AND ISREFERENCE THEN e$ = refer(e$, sourcetyp, 0)
                        IF Error_Happened THEN EXIT FUNCTION

                        arg1Typ& = sourcetyp ' save the type of the 1st argument
                        r$ = e$ ' save the partitially generated C code
                        e$ = _STR_EMPTY

                        GOTO dontevaluate
                    ELSEIF curarg = 2 THEN
                        IF NOT Type_IsArithmetic(sourcetyp) _ORELSE Type_IsUDTContainer(sourcetyp) THEN
                            Give_Error "Expected numeric argument"
                            EXIT FUNCTION
                        END IF

                        IF sourcetyp AND ISREFERENCE THEN e$ = refer(e$, sourcetyp, 0)
                        IF Error_Happened THEN EXIT FUNCTION

                        arg2Typ& = sourcetyp ' save the type of the 2nd argument
                        r$ = r$ + e$ ' save the partitially generated C code
                        e$ = _STR_EMPTY

                        GOTO dontevaluate
                    ELSEIF curarg = 3 THEN
                        IF NOT Type_IsArithmetic(sourcetyp) _ORELSE Type_IsUDTContainer(sourcetyp) THEN
                            Give_Error "Expected numeric argument"
                            EXIT FUNCTION
                        END IF

                        IF sourcetyp AND ISREFERENCE THEN e$ = refer(e$, sourcetyp, 0)
                        IF Error_Happened THEN EXIT FUNCTION

                        typ& = Type_PromoteArithmeticType(Type_PromoteArithmeticType(arg1Typ&, arg2Typ&), sourcetyp)
                        r$ = "func_clamp<" + Type_GetCppArithmeticType(typ&) + ">(" + r$ + e$ + ")"
                        IF Error_Happened THEN EXIT FUNCTION

                        GOTO evalfuncspecial
                    END IF
                END IF

                ' ROR & ROL support
                IF n$ = "_ROR" _ORELSE n$ = "_ROL" THEN
                    rotlr_n$ = LCASE$(RIGHT$(n$, 3)) ' we'll need this to construct the C call

                    IF curarg = 1 THEN ' first parameter
                        IF NOT Type_IsIntegral(sourcetyp) _ORELSE Type_IsUDTContainer(sourcetyp) THEN
                            Give_Error "Expected non-floating-point numeric argument"
                            EXIT FUNCTION
                        END IF

                        IF sourcetyp AND ISREFERENCE THEN e$ = refer(e$, sourcetyp, 0)
                        IF Error_Happened THEN EXIT FUNCTION

                        SELECT CASE Type_GetSizeInBits(sourcetyp)
                            CASE 8
                                e$ = "func__" + rotlr_n$ + "<uint8_t>(" + e$
                                typ& = UBYTETYPE - ISPOINTER ' the return type is passed back up to the caller
                            CASE 16
                                e$ = "func__" + rotlr_n$ + "<uint16_t>(" + e$
                                typ& = UINTEGERTYPE - ISPOINTER
                            CASE 32
                                e$ = "func__" + rotlr_n$ + "<uint32_t>(" + e$
                                typ& = ULONGTYPE - ISPOINTER
                            CASE 64
                                e$ = "func__" + rotlr_n$ + "<uint64_t>(" + e$
                                typ& = UINTEGER64TYPE - ISPOINTER
                            CASE ELSE
                                Give_Error "Unsupported integral type size"
                                EXIT FUNCTION
                        END SELECT

                        r$ = e$ ' save whatever syntax he have so far
                        e$ = _STR_EMPTY ' this must be cleared so that it is not repeated when we get to parameter 2

                        GOTO dontevaluate ' don't evaluate until we get the second parameter
                    ELSEIF curarg = 2 THEN ' second parameter
                        IF NOT Type_IsIntegral(sourcetyp) _ORELSE Type_IsUDTContainer(sourcetyp) THEN
                            Give_Error "Expected non-floating-point numeric argument"
                            EXIT FUNCTION
                        END IF

                        IF sourcetyp AND ISREFERENCE THEN e$ = refer(e$, sourcetyp, 0)
                        IF Error_Happened THEN EXIT FUNCTION

                        r$ = r$ + e$ + ")"

                        GOTO evalfuncspecial ' evaluate now that we have everything
                    END IF
                END IF

                ' UCHARPOS special case for arg 2
                IF n$ = "_UCHARPOS" THEN
                    IF curarg = 2 THEN
                        ' It must be an array
                        IF (sourcetyp AND ISREFERENCE) = 0 OR (sourcetyp AND ISARRAY) = 0 THEN
                            Give_Error "Expected LONG array-name"
                            EXIT FUNCTION
                        END IF

                        ' Cannot be one of these
                        IF (sourcetyp AND ISSTRING) OR (sourcetyp AND ISFLOAT) OR (sourcetyp AND ISOFFSET) OR (sourcetyp AND ISUDT) OR (sourcetyp AND UDTMASK) <> 32 THEN
                            Give_Error "Expected LONG array-name"
                            EXIT FUNCTION
                        END IF

                        e$ = evaluatetotyp(e2$, -2) ' get byte_element_struct

                        GOTO dontevaluate
                    END IF
                END IF

                '***special case***
                IF n$ = "_MEM" THEN
                    IF curarg = 1 THEN
                        IF args = 1 THEN
                            targettyp = -7
                        END IF
                        IF args = 2 THEN
                            r$ = RTRIM$(id2.callname) + "_at_offset" + RIGHT$(r$, LEN(r$) - LEN(RTRIM$(id2.callname)))
                            IF (sourcetyp AND ISOFFSET) = 0 THEN Give_Error "Expected _MEM(_OFFSET-value,...)": EXIT FUNCTION
                        END IF
                    END IF
                END IF

                '*special case*
                IF n$ = "_OFFSET" THEN
                    IF (sourcetyp AND ISREFERENCE) = 0 THEN
                        Give_Error "_OFFSET expects the name of a variable/array": EXIT FUNCTION
                    END IF
                    IF (sourcetyp AND ISARRAY) THEN
                        IF (sourcetyp AND ISOFFSETINBITS) THEN Give_Error "_OFFSET cannot reference _BIT type arrays": EXIT FUNCTION
                    END IF
                    r$ = "((uptrszint)(" + evaluatetotyp$(e2$, -6) + "))"
                    IF Error_Happened THEN EXIT FUNCTION
                    typ& = UOFFSETTYPE - ISPOINTER
                    GOTO evalfuncspecial
                END IF '_OFFSET


                '*special case*
                IF n$ = "ENVIRON" THEN
                    IF sourcetyp AND ISSTRING THEN
                        IF sourcetyp AND ISREFERENCE THEN e$ = refer(e$, sourcetyp, 0)
                        IF Error_Happened THEN EXIT FUNCTION
                        GOTO dontevaluate
                    END IF
                END IF

                '*special case*
                IF n$ = "LEN" THEN
                    typ& = LONGTYPE - ISPOINTER
                    IF (sourcetyp AND ISREFERENCE) = 0 THEN
                        'could be a string expression
                        IF sourcetyp AND ISSTRING THEN
                            r$ = "((int32)(" + e$ + ")->len)"
                            GOTO evalfuncspecial
                        END IF
                        Give_Error "String expression or variable name required in LEN statement": EXIT FUNCTION
                    END IF
                    r$ = evaluatetotyp$(e2$, -5) 'use evaluatetotyp to get 'element' size
                    IF Error_Happened THEN EXIT FUNCTION
                    GOTO evalfuncspecial
                END IF


                '*special case*
                IF n$ = "_BIN" THEN
                    IF RTRIM$(id2.musthave) = "$" THEN
                        bits = sourcetyp AND UDTMASK

                        IF (sourcetyp AND ISSTRING) THEN Give_Error "Expected numeric value": EXIT FUNCTION
                        wasref = 0
                        IF (sourcetyp AND ISREFERENCE) THEN e$ = refer(e$, sourcetyp, 0): wasref = 1
                        IF Error_Happened THEN EXIT FUNCTION
                        bits = sourcetyp AND UDTMASK
                        IF (sourcetyp AND ISOFFSETINBITS) THEN
                            e$ = "func__bin(" + e$ + "," + _TOSTR$(bits) + ")"
                        ELSE
                            IF (sourcetyp AND ISFLOAT) THEN
                                e$ = "func__bin_float(" + e$ + ")"
                            ELSE
                                IF bits = 64 THEN
                                    IF wasref = 0 THEN bits = 0
                                END IF
                                e$ = "func__bin(" + e$ + "," + _TOSTR$(bits) + ")"
                            END IF
                        END IF
                        typ& = STRINGTYPE - ISPOINTER
                        r$ = e$
                        GOTO evalfuncspecial
                    END IF
                END IF

                '*special case*
                IF n$ = "OCT" THEN
                    IF RTRIM$(id2.musthave) = "$" THEN
                        bits = sourcetyp AND UDTMASK

                        IF (sourcetyp AND ISSTRING) THEN Give_Error "Expected numeric value": EXIT FUNCTION
                        wasref = 0
                        IF (sourcetyp AND ISREFERENCE) THEN e$ = refer(e$, sourcetyp, 0): wasref = 1
                        IF Error_Happened THEN EXIT FUNCTION
                        bits = sourcetyp AND UDTMASK
                        IF (sourcetyp AND ISOFFSETINBITS) THEN
                            e$ = "func_oct(" + e$ + "," + _TOSTR$(bits) + ")"
                        ELSE
                            IF (sourcetyp AND ISFLOAT) THEN
                                e$ = "func_oct_float(" + e$ + ")"
                            ELSE
                                IF bits = 64 THEN
                                    IF wasref = 0 THEN bits = 0
                                END IF
                                e$ = "func_oct(" + e$ + "," + _TOSTR$(bits) + ")"
                            END IF
                        END IF
                        typ& = STRINGTYPE - ISPOINTER
                        r$ = e$
                        GOTO evalfuncspecial
                    END IF
                END IF

                '*special case*
                IF n$ = "HEX" THEN
                    IF RTRIM$(id2.musthave) = "$" THEN
                        bits = sourcetyp AND UDTMASK
                        IF (sourcetyp AND ISSTRING) THEN Give_Error "Expected numeric value": EXIT FUNCTION
                        wasref = 0
                        IF (sourcetyp AND ISREFERENCE) THEN e$ = refer(e$, sourcetyp, 0): wasref = 1
                        IF Error_Happened THEN EXIT FUNCTION
                        bits = sourcetyp AND UDTMASK
                        IF (sourcetyp AND ISOFFSETINBITS) THEN
                            chars = (bits + 3) \ 4
                            e$ = "func_hex(" + e$ + "," + _TOSTR$(chars) + ")"
                        ELSE
                            IF (sourcetyp AND ISFLOAT) THEN
                                e$ = "func_hex_float(" + e$ + ")"
                            ELSE
                                IF bits = 8 THEN chars = 2
                                IF bits = 16 THEN chars = 4
                                IF bits = 32 THEN chars = 8
                                IF bits = 64 THEN
                                    IF wasref = 1 THEN chars = 16 ELSE chars = 0
                                END IF
                                e$ = "func_hex(" + e$ + "," + _TOSTR$(chars) + ")"
                            END IF
                        END IF
                        typ& = STRINGTYPE - ISPOINTER
                        r$ = e$
                        GOTO evalfuncspecial
                    END IF
                END IF


                '*special case*
                IF n$ = "EXP" THEN
                    bits = sourcetyp AND UDTMASK
                    IF (sourcetyp AND ISSTRING) THEN Give_Error "Expected numeric value": EXIT FUNCTION
                    IF (sourcetyp AND ISREFERENCE) THEN e$ = refer(e$, sourcetyp, 0)
                    IF Error_Happened THEN EXIT FUNCTION
                    bits = sourcetyp AND UDTMASK
                    typ& = SINGLETYPE - ISPOINTER
                    IF (sourcetyp AND ISFLOAT) THEN
                        IF bits = 32 THEN e$ = "func_exp_single(" + e$ + ")" ELSE e$ = "func_exp_float(" + e$ + ")": typ& = FLOATTYPE - ISPOINTER
                    ELSE
                        IF (sourcetyp AND ISOFFSETINBITS) THEN
                            e$ = "func_exp_float(" + e$ + ")": typ& = FLOATTYPE - ISPOINTER
                        ELSE
                            IF bits <= 16 THEN e$ = "func_exp_single(" + e$ + ")" ELSE e$ = "func_exp_float(" + e$ + ")": typ& = FLOATTYPE - ISPOINTER
                        END IF
                    END IF
                    r$ = e$
                    GOTO evalfuncspecial
                END IF

                '*special case*
                IF n$ = "INT" THEN
                    IF (sourcetyp AND ISSTRING) THEN Give_Error "Expected numeric value": EXIT FUNCTION
                    IF (sourcetyp AND ISREFERENCE) THEN e$ = refer(e$, sourcetyp, 0)
                    IF Error_Happened THEN EXIT FUNCTION
                    'establish which function (if any!) should be used
                    IF (sourcetyp AND ISFLOAT) THEN e$ = "std::floor(" + e$ + ")" ELSE e$ = "(" + e$ + ")"
                    r$ = e$
                    typ& = sourcetyp
                    GOTO evalfuncspecial
                END IF

                '*special case*
                IF n$ = "FIX" THEN
                    IF (sourcetyp AND ISSTRING) THEN Give_Error "Expected numeric value": EXIT FUNCTION
                    IF (sourcetyp AND ISREFERENCE) THEN e$ = refer(e$, sourcetyp, 0)
                    IF Error_Happened THEN EXIT FUNCTION
                    'establish which function (if any!) should be used
                    bits = sourcetyp AND UDTMASK
                    IF (sourcetyp AND ISFLOAT) THEN
                        IF bits > 64 THEN e$ = "func_fix_float(" + e$ + ")" ELSE e$ = "func_fix_double(" + e$ + ")"
                    ELSE
                        e$ = "(" + e$ + ")"
                    END IF
                    r$ = e$
                    typ& = sourcetyp
                    GOTO evalfuncspecial
                END IF

                '*special case*
                IF n$ = "_ROUND" THEN
                    IF (sourcetyp AND ISSTRING) THEN Give_Error "Expected numeric value": EXIT FUNCTION
                    IF (sourcetyp AND ISREFERENCE) THEN e$ = refer(e$, sourcetyp, 0)
                    IF Error_Happened THEN EXIT FUNCTION
                    'establish which function (if any!) should be used
                    IF (sourcetyp AND ISFLOAT) THEN
                        bits = sourcetyp AND UDTMASK
                        IF bits > 64 THEN e$ = "func_round_float(" + e$ + ")" ELSE e$ = "func_round_double(" + e$ + ")"
                    ELSE
                        e$ = "(" + e$ + ")"
                    END IF
                    r$ = e$
                    typ& = 64&
                    IF (sourcetyp AND ISOFFSET) THEN
                        IF sourcetyp AND ISUNSIGNED THEN typ& = UOFFSETTYPE - ISPOINTER ELSE typ& = OFFSETTYPE - ISPOINTER
                    END IF
                    GOTO evalfuncspecial
                END IF


                '*special case*
                IF n$ = "CDBL" THEN
                    IF (sourcetyp AND ISSTRING) THEN Give_Error "Expected numeric value": EXIT FUNCTION
                    IF (sourcetyp AND ISREFERENCE) THEN e$ = refer(e$, sourcetyp, 0)
                    IF Error_Happened THEN EXIT FUNCTION
                    'establish which function (if any!) should be used
                    bits = sourcetyp AND UDTMASK
                    IF (sourcetyp AND ISFLOAT) THEN
                        IF bits > 64 THEN e$ = "func_cdbl_float(" + e$ + ")"
                    ELSE
                        e$ = "((double)(" + e$ + "))"
                    END IF
                    r$ = e$
                    typ& = DOUBLETYPE - ISPOINTER
                    GOTO evalfuncspecial
                END IF

                '*special case*
                IF n$ = "CSNG" THEN
                    IF (sourcetyp AND ISSTRING) THEN Give_Error "Expected numeric value": EXIT FUNCTION
                    IF (sourcetyp AND ISREFERENCE) THEN e$ = refer(e$, sourcetyp, 0)
                    IF Error_Happened THEN EXIT FUNCTION
                    'establish which function (if any!) should be used
                    bits = sourcetyp AND UDTMASK
                    IF (sourcetyp AND ISFLOAT) THEN
                        IF bits = 64 THEN e$ = "func_csng_double(" + e$ + ")"
                        IF bits > 64 THEN e$ = "func_csng_float(" + e$ + ")"
                    ELSE
                        e$ = "((double)(" + e$ + "))"
                    END IF
                    r$ = e$
                    typ& = SINGLETYPE - ISPOINTER
                    GOTO evalfuncspecial
                END IF


                '*special case*
                IF n$ = "CLNG" THEN
                    IF (sourcetyp AND ISSTRING) THEN Give_Error "Expected numeric value": EXIT FUNCTION
                    IF (sourcetyp AND ISREFERENCE) THEN e$ = refer(e$, sourcetyp, 0)
                    IF Error_Happened THEN EXIT FUNCTION
                    'establish which function (if any!) should be used
                    bits = sourcetyp AND UDTMASK
                    IF (sourcetyp AND ISFLOAT) THEN
                        IF bits > 64 THEN e$ = "func_clng_float(" + e$ + ")" ELSE e$ = "func_clng_double(" + e$ + ")"
                    ELSE 'integer
                        IF (sourcetyp AND ISUNSIGNED) THEN
                            IF bits = 32 THEN e$ = "func_clng_ulong(" + e$ + ")"
                            IF bits > 32 THEN e$ = "func_clng_uint64(" + e$ + ")"
                        ELSE 'signed
                            IF bits > 32 THEN e$ = "func_clng_int64(" + e$ + ")"
                        END IF
                    END IF
                    r$ = e$
                    typ& = 32&
                    GOTO evalfuncspecial
                END IF

                '*special case*
                IF n$ = "CINT" THEN
                    IF (sourcetyp AND ISSTRING) THEN Give_Error "Expected numeric value": EXIT FUNCTION
                    IF (sourcetyp AND ISREFERENCE) THEN e$ = refer(e$, sourcetyp, 0)
                    IF Error_Happened THEN EXIT FUNCTION
                    'establish which function (if any!) should be used
                    bits = sourcetyp AND UDTMASK
                    IF (sourcetyp AND ISFLOAT) THEN
                        IF bits > 64 THEN e$ = "func_cint_float(" + e$ + ")" ELSE e$ = "func_cint_double(" + e$ + ")"
                    ELSE 'integer
                        IF (sourcetyp AND ISUNSIGNED) THEN
                            IF bits > 15 AND bits <= 32 THEN e$ = "func_cint_ulong(" + e$ + ")"
                            IF bits > 32 THEN e$ = "func_cint_uint64(" + e$ + ")"
                        ELSE 'signed
                            IF bits > 16 AND bits <= 32 THEN e$ = "func_cint_long(" + e$ + ")"
                            IF bits > 32 THEN e$ = "func_cint_int64(" + e$ + ")"
                        END IF
                    END IF
                    r$ = e$
                    typ& = 16&
                    GOTO evalfuncspecial
                END IF

                '*special case MKI,MKL,MKS,MKD,_MK (part #2)
                mktype = 0
                size = 0
                IF n$ = "MKI" THEN mktype = 1: mktype$ = "%"
                IF n$ = "MKL" THEN mktype = 2: mktype$ = "&"
                IF n$ = "MKS" THEN mktype = 3: mktype$ = "!"
                IF n$ = "MKD" THEN mktype = 4: mktype$ = "#"
                IF n$ = "_MK" THEN mktype = -1
                IF mktype THEN
                    IF mktype <> -1 OR curarg = 2 THEN
                        'both _MK and trad. process the following
                        qtyp& = 0
                        IF mktype$ = "%%" THEN ctype$ = "b": qtyp& = BYTETYPE - ISPOINTER
                        IF mktype$ = "~%%" THEN ctype$ = "ub": qtyp& = UBYTETYPE - ISPOINTER
                        IF mktype$ = "%" THEN ctype$ = "i": qtyp& = INTEGERTYPE - ISPOINTER
                        IF mktype$ = "~%" THEN ctype$ = "ui": qtyp& = UINTEGERTYPE - ISPOINTER
                        IF mktype$ = "&" THEN ctype$ = "l": qtyp& = LONGTYPE - ISPOINTER
                        IF mktype$ = "~&" THEN ctype$ = "ul": qtyp& = ULONGTYPE - ISPOINTER
                        IF mktype$ = "&&" THEN ctype$ = "i64": qtyp& = INTEGER64TYPE - ISPOINTER
                        IF mktype$ = "~&&" THEN ctype$ = "ui64": qtyp& = UINTEGER64TYPE - ISPOINTER
                        IF mktype$ = "!" THEN ctype$ = "s": qtyp& = SINGLETYPE - ISPOINTER
                        IF mktype$ = "#" THEN ctype$ = "d": qtyp& = DOUBLETYPE - ISPOINTER
                        IF mktype$ = "##" THEN ctype$ = "f": qtyp& = FLOATTYPE - ISPOINTER
                        IF mktype$ = "%&" THEN ctype$ = "o": qtyp& = OFFSETTYPE - ISPOINTER
                        IF mktype$ = "~%&" THEN ctype$ = "uo": qtyp& = UOFFSETTYPE - ISPOINTER
                        IF LEFT$(mktype$, 2) = "~`" THEN ctype$ = "ubit": qtyp& = UINTEGER64TYPE - ISPOINTER: size = VAL(RIGHT$(mktype$, LEN(mktype$) - 2))
                        IF LEFT$(mktype$, 1) = "`" THEN ctype$ = "bit": qtyp& = INTEGER64TYPE - ISPOINTER: size = VAL(RIGHT$(mktype$, LEN(mktype$) - 1))
                        IF qtyp& = 0 THEN Give_Error "_MK only accepts numeric types": EXIT FUNCTION
                        IF size THEN
                            r$ = ctype$ + "2string(" + _TOSTR$(size) + ","
                        ELSE
                            r$ = ctype$ + "2string("
                        END IF
                        noComma = 1
                        targettyp = qtyp&
                    END IF
                END IF

                '*special case CVI,CVL,CVS,CVD,_CV (part #2)
                cvtype = 0
                IF n$ = "CVI" THEN cvtype = 1: cvtype$ = "%"
                IF n$ = "CVL" THEN cvtype = 2: cvtype$ = "&"
                IF n$ = "CVS" THEN cvtype = 3: cvtype$ = "!"
                IF n$ = "CVD" THEN cvtype = 4: cvtype$ = "#"
                IF n$ = "_CV" THEN cvtype = -1
                IF cvtype THEN
                    IF cvtype <> -1 OR curarg = 2 THEN
                        IF (sourcetyp AND ISSTRING) = 0 THEN Give_Error n$ + " requires a STRING argument": EXIT FUNCTION
                        IF (sourcetyp AND ISREFERENCE) THEN e$ = refer(e$, sourcetyp, 0)
                        IF Error_Happened THEN EXIT FUNCTION
                        typ& = 0
                        IF cvtype$ = "%%" THEN ctype$ = "b": typ& = BYTETYPE - ISPOINTER
                        IF cvtype$ = "~%%" THEN ctype$ = "ub": typ& = UBYTETYPE - ISPOINTER
                        IF cvtype$ = "%" THEN ctype$ = "i": typ& = INTEGERTYPE - ISPOINTER
                        IF cvtype$ = "~%" THEN ctype$ = "ui": typ& = UINTEGERTYPE - ISPOINTER
                        IF cvtype$ = "&" THEN ctype$ = "l": typ& = LONGTYPE - ISPOINTER
                        IF cvtype$ = "~&" THEN ctype$ = "ul": typ& = ULONGTYPE - ISPOINTER
                        IF cvtype$ = "&&" THEN ctype$ = "i64": typ& = INTEGER64TYPE - ISPOINTER
                        IF cvtype$ = "~&&" THEN ctype$ = "ui64": typ& = UINTEGER64TYPE - ISPOINTER
                        IF cvtype$ = "!" THEN ctype$ = "s": typ& = SINGLETYPE - ISPOINTER
                        IF cvtype$ = "#" THEN ctype$ = "d": typ& = DOUBLETYPE - ISPOINTER
                        IF cvtype$ = "##" THEN ctype$ = "f": typ& = FLOATTYPE - ISPOINTER
                        IF cvtype$ = "%&" THEN ctype$ = "o": typ& = OFFSETTYPE - ISPOINTER
                        IF cvtype$ = "~%&" THEN ctype$ = "uo": typ& = UOFFSETTYPE - ISPOINTER
                        IF LEFT$(cvtype$, 2) = "~`" THEN ctype$ = "ubit": typ& = UINTEGER64TYPE - ISPOINTER: size = VAL(RIGHT$(cvtype$, LEN(cvtype$) - 2))
                        IF LEFT$(cvtype$, 1) = "`" THEN ctype$ = "bit": typ& = INTEGER64TYPE - ISPOINTER: size = VAL(RIGHT$(cvtype$, LEN(cvtype$) - 1))
                        IF typ& = 0 THEN Give_Error "_CV cannot return STRING type!": EXIT FUNCTION
                        IF ctype$ = "bit" OR ctype$ = "ubit" THEN
                            r$ = "string2" + ctype$ + "(" + e$ + "," + _TOSTR$(size) + ")"
                        ELSE
                            r$ = "string2" + ctype$ + "(" + e$ + ")"
                        END IF
                        GOTO evalfuncspecial
                    END IF
                END IF

                '*special case
                IF RTRIM$(id2.n) = "STRING" THEN
                    IF curarg = 2 THEN
                        IF (sourcetyp AND ISSTRING) THEN
                            IF (sourcetyp AND ISREFERENCE) THEN e$ = refer(e$, sourcetyp, 0)
                            IF Error_Happened THEN EXIT FUNCTION
                            sourcetyp = 64&
                            e$ = "(" + e$ + "->chr[0])"
                        END IF
                    END IF
                END IF

                '*special case
                IF RTRIM$(id2.n) = "SADD" THEN
                    IF (sourcetyp AND ISREFERENCE) = 0 THEN
                        Give_Error "SADD only accepts variable-length string variables": EXIT FUNCTION
                    END IF
                    IF (sourcetyp AND ISFIXEDLENGTH) THEN
                        Give_Error "SADD only accepts variable-length string variables": EXIT FUNCTION
                    END IF
                    IF (sourcetyp AND ISINCONVENTIONALMEMORY) = 0 THEN
                        recompile = 1
                        cmemlist(VAL(e$)) = 1
                        r$ = "[CONVENTIONAL_MEMORY_REQUIRED]"
                        typ& = 64&
                        GOTO evalfuncspecial
                    END IF
                    r$ = refer(e$, sourcetyp, 0)
                    IF Error_Happened THEN EXIT FUNCTION
                    r$ = "((unsigned short)(" + r$ + "->chr-&cmem[1280]))"
                    typ& = 64&
                    GOTO evalfuncspecial
                END IF

                '*special case
                IF RTRIM$(id2.n) = "VARPTR" THEN
                    IF (sourcetyp AND ISREFERENCE) = 0 THEN
                        Give_Error "Expected reference to a variable/array": EXIT FUNCTION
                    END IF

                    IF RTRIM$(id2.musthave) = "$" THEN
                        IF (sourcetyp AND ISINCONVENTIONALMEMORY) = 0 THEN
                            recompile = 1
                            cmemlist(VAL(e$)) = 1
                            r$ = "[CONVENTIONAL_MEMORY_REQUIRED]"
                            typ& = ISSTRING
                            GOTO evalfuncspecial
                        END IF

                        IF (sourcetyp AND ISARRAY) THEN
                            IF (sourcetyp AND ISSTRING) = 0 THEN Give_Error "VARPTR$ only accepts variable-length string arrays": EXIT FUNCTION
                            IF (sourcetyp AND ISFIXEDLENGTH) THEN Give_Error "VARPTR$ only accepts variable-length string arrays": EXIT FUNCTION
                        END IF

                        'must be a simple variable
                        '!assuming it is in cmem in DBLOCK
                        r$ = refer(e$, sourcetyp, 1)
                        IF Error_Happened THEN EXIT FUNCTION
                        IF (sourcetyp AND ISSTRING) THEN
                            IF (sourcetyp AND ISARRAY) THEN r$ = refer(e$, sourcetyp, 0)
                            IF Error_Happened THEN EXIT FUNCTION
                            r$ = r$ + "->cmem_descriptor_offset"
                            t = 3
                        ELSE
                            r$ = "((unsigned short)(((uint8*)" + r$ + ")-&cmem[1280]))"
                            '*top bit on=unsigned
                            '*second top bit on=bit-value (lower bits indicate the size)
                            'BYTE=1
                            'INTEGER=2
                            'STRING=3
                            'SINGLE=4
                            'INT64=5
                            'FLOAT=6
                            'DOUBLE=8
                            'LONG=20
                            'BIT=64+n
                            t = 0
                            IF (sourcetyp AND ISUNSIGNED) THEN t = t + 128
                            IF (sourcetyp AND ISOFFSETINBITS) THEN
                                t = t + 64
                                t = t + (sourcetyp AND 63)
                            ELSE
                                bits = sourcetyp AND UDTMASK
                                IF (sourcetyp AND ISFLOAT) THEN
                                    IF bits = 32 THEN t = t + 4
                                    IF bits = 64 THEN t = t + 8
                                    IF bits = 256 THEN t = t + 6
                                ELSE
                                    IF bits = 8 THEN t = t + 1
                                    IF bits = 16 THEN t = t + 2
                                    IF bits = 32 THEN t = t + 20
                                    IF bits = 64 THEN t = t + 5
                                END IF
                            END IF
                        END IF
                        r$ = "func_varptr_helper(" + _TOSTR$(t) + "," + r$ + ")"
                        typ& = ISSTRING
                        GOTO evalfuncspecial
                    END IF 'end of varptr$











                    'VARPTR
                    IF (sourcetyp AND ISINCONVENTIONALMEMORY) = 0 THEN
                        recompile = 1
                        cmemlist(VAL(e$)) = 1
                        r$ = "[CONVENTIONAL_MEMORY_REQUIRED]"
                        typ& = 64&
                        GOTO evalfuncspecial
                    END IF

                    IF (sourcetyp AND ISARRAY) THEN
                        IF (sourcetyp AND ISOFFSETINBITS) THEN Give_Error "VARPTR cannot reference _BIT type arrays": EXIT FUNCTION

                        'string array?
                        IF (sourcetyp AND ISSTRING) THEN
                            IF (sourcetyp AND ISFIXEDLENGTH) THEN
                                getid VAL(e$)
                                IF Error_Happened THEN EXIT FUNCTION
                                m = id.tsize
                                index$ = RIGHT$(e$, LEN(e$) - INSTR(e$, sp3))
                                typ = 64&
                                r$ = "((" + index$ + ")*" + _TOSTR$(m) + ")"
                                GOTO evalfuncspecial
                            ELSE
                                'return the offset of the string's descriptor
                                r$ = refer(e$, sourcetyp, 0)
                                IF Error_Happened THEN EXIT FUNCTION
                                r$ = r$ + "->cmem_descriptor_offset"
                                typ = 64&
                                GOTO evalfuncspecial
                            END IF
                        END IF

                        IF sourcetyp AND ISUDT THEN
                            e$ = RIGHT$(e$, LEN(e$) - INSTR(e$, sp3)) 'skip idnumber
                            e$ = RIGHT$(e$, LEN(e$) - INSTR(e$, sp3)) 'skip u
                            o$ = RIGHT$(e$, LEN(e$) - INSTR(e$, sp3)) 'skip e
                            typ = 64&
                            r$ = "(" + o$ + ")"
                            GOTO evalfuncspecial
                        END IF

                        'non-UDT array
                        m = (sourcetyp AND UDTMASK) \ 8 'calculate size multiplier
                        index$ = RIGHT$(e$, LEN(e$) - INSTR(e$, sp3))
                        typ = 64&
                        r$ = "((" + index$ + ")*" + _TOSTR$(m) + ")"
                        GOTO evalfuncspecial

                    END IF

                    'not an array

                    IF sourcetyp AND ISUDT THEN
                        r$ = refer(e$, sourcetyp, 1)
                        IF Error_Happened THEN EXIT FUNCTION
                        e$ = RIGHT$(e$, LEN(e$) - INSTR(e$, sp3)) 'skip idnumber
                        e$ = RIGHT$(e$, LEN(e$) - INSTR(e$, sp3)) 'skip u
                        o$ = RIGHT$(e$, LEN(e$) - INSTR(e$, sp3)) 'skip e
                        typ = 64&

                        'if sub/func arg, may not be in DBLOCK
                        getid VAL(e$)
                        IF Error_Happened THEN EXIT FUNCTION
                        IF id.sfarg THEN 'could be in DBLOCK
                            'note: segment could be the closest segment to UDT element or the base of DBLOCK
                            r$ = "varptr_dblock_check(((uint8*)" + r$ + ")+(" + o$ + "))"
                        ELSE 'definitely in DBLOCK
                            'give offset relative to DBLOCK
                            r$ = "((unsigned short)(((uint8*)" + r$ + ") - &cmem[1280] + (" + o$ + ") ))"
                        END IF

                        GOTO evalfuncspecial
                    END IF

                    typ = 64&
                    r$ = refer(e$, sourcetyp, 1)
                    IF Error_Happened THEN EXIT FUNCTION
                    IF (sourcetyp AND ISSTRING) THEN
                        IF (sourcetyp AND ISFIXEDLENGTH) THEN

                            'if sub/func arg, may not be in DBLOCK
                            getid VAL(e$)
                            IF Error_Happened THEN EXIT FUNCTION
                            IF id.sfarg THEN 'could be in DBLOCK
                                r$ = "varptr_dblock_check(" + r$ + "->chr)"
                            ELSE 'definitely in DBLOCK
                                r$ = "((unsigned short)(" + r$ + "->chr-&cmem[1280]))"
                            END IF

                        ELSE
                            r$ = r$ + "->cmem_descriptor_offset"
                        END IF
                        GOTO evalfuncspecial
                    END IF

                    'single, simple variable
                    'if sub/func arg, may not be in DBLOCK
                    getid VAL(e$)
                    IF Error_Happened THEN EXIT FUNCTION
                    IF id.sfarg THEN 'could be in DBLOCK
                        r$ = "varptr_dblock_check((uint8*)" + r$ + ")"
                    ELSE 'definitely in DBLOCK
                        r$ = "((unsigned short)(((uint8*)" + r$ + ")-&cmem[1280]))"
                    END IF

                    GOTO evalfuncspecial
                END IF

                '*special case*
                IF RTRIM$(id2.n) = "VARSEG" THEN
                    IF (sourcetyp AND ISREFERENCE) = 0 THEN
                        Give_Error "Expected reference to a variable/array": EXIT FUNCTION
                    END IF
                    IF (sourcetyp AND ISINCONVENTIONALMEMORY) = 0 THEN
                        recompile = 1
                        cmemlist(VAL(e$)) = 1
                        r$ = "[CONVENTIONAL_MEMORY_REQUIRED]"
                        typ& = 64&
                        GOTO evalfuncspecial
                    END IF
                    'array?
                    IF (sourcetyp AND ISARRAY) THEN
                        IF (sourcetyp AND ISFIXEDLENGTH) = 0 THEN
                            IF (sourcetyp AND ISSTRING) THEN
                                r$ = "80"
                                typ = 64&
                                GOTO evalfuncspecial
                            END IF
                        END IF
                        typ = 64&
                        r$ = "( ( ((ptrszint)(" + refer(e$, sourcetyp, 1) + "[0])) - ((ptrszint)(&cmem[0])) ) /16)"
                        IF Error_Happened THEN EXIT FUNCTION
                        GOTO evalfuncspecial
                    END IF

                    'single variable/(var-len)string/udt? (usually stored in DBLOCK)
                    typ = 64&
                    'if sub/func arg, may not be in DBLOCK
                    getid VAL(e$)
                    IF Error_Happened THEN EXIT FUNCTION
                    IF id.sfarg <> 0 AND (sourcetyp AND ISSTRING) = 0 THEN
                        IF sourcetyp AND ISUDT THEN
                            r$ = refer(e$, sourcetyp, 1)
                            IF Error_Happened THEN EXIT FUNCTION
                            e$ = RIGHT$(e$, LEN(e$) - INSTR(e$, sp3)) 'skip idnumber
                            e$ = RIGHT$(e$, LEN(e$) - INSTR(e$, sp3)) 'skip u
                            o$ = RIGHT$(e$, LEN(e$) - INSTR(e$, sp3)) 'skip e
                            r$ = "varseg_dblock_check(((uint8*)" + r$ + ")+(" + o$ + "))"
                        ELSE
                            r$ = "varseg_dblock_check((uint8*)" + refer(e$, sourcetyp, 1) + ")"
                            IF Error_Happened THEN EXIT FUNCTION
                        END IF
                    ELSE
                        'can be assumed to be in DBLOCK
                        r$ = "80"
                    END IF
                    GOTO evalfuncspecial
                END IF 'varseg















                'note: this code has already been called...
                '------------------------------------------------------------------------------------------------------------
                'e2$ = e$
                'e$ = evaluate(e$, sourcetyp)
                '------------------------------------------------------------------------------------------------------------

                'note: this comment makes no sense...
                'any numeric variable, but it must be type-specified

                IF targettyp = -2 THEN
                    e$ = evaluatetotyp(e2$, -2)
                    IF Error_Happened THEN EXIT FUNCTION
                    GOTO dontevaluate
                END IF '-2

                IF targettyp = -7 THEN
                    e$ = evaluatetotyp(e2$, -7)
                    IF Error_Happened THEN EXIT FUNCTION
                    GOTO dontevaluate
                END IF '-7

                IF targettyp = -8 THEN
                    e$ = evaluatetotyp(e2$, -8)
                    IF Error_Happened THEN EXIT FUNCTION
                    GOTO dontevaluate
                END IF '-8

                'note: this is used for functions like STR(...) which accept all types...
                explicitreference = 0
                IF targettyp = -1 THEN
                    explicitreference = 1
                    IF (sourcetyp AND ISSTRING) THEN Give_Error "Number required for function": EXIT FUNCTION
                    targettyp = sourcetyp
                    IF (targettyp AND ISPOINTER) THEN targettyp = targettyp - ISPOINTER
                END IF

                'pointer?
                IF (targettyp AND ISPOINTER) THEN
                    IF dereference = 0 THEN 'check dereferencing wasn't used

                        'note: array pointer
                        IF (targettyp AND ISARRAY) THEN
                            IF (sourcetyp AND ISREFERENCE) = 0 THEN Give_Error "Expected arrayname()": EXIT FUNCTION
                            IF (sourcetyp AND ISARRAY) = 0 THEN Give_Error "Expected arrayname()": EXIT FUNCTION
                            IF Debug THEN PRINT #9, "evaluatefunc:array reference:[" + e$ + "]"

                            'check arrays are of same type
                            targettyp2 = targettyp: sourcetyp2 = sourcetyp
                            targettyp2 = targettyp2 AND (UDTMASK + ISOFFSETINBITS + ISUDT + ISSTRING + ISFIXEDLENGTH + ISFLOAT)
                            sourcetyp2 = sourcetyp2 AND (UDTMASK + ISOFFSETINBITS + ISUDT + ISSTRING + ISFIXEDLENGTH + ISFLOAT)
                            IF sourcetyp2 <> targettyp2 THEN Give_Error "Incorrect array type passed to function": EXIT FUNCTION

                            member_element_id = 0

                            'check arrayname was followed by '()'
                            IF RIGHT$(e$, 2) = sp3 + "0" THEN
                                ' classic whole-array reference: array()
                            ELSE
                                s1 = INSTR(e$, sp3)
                                IF s1 THEN
                                    s2 = INSTR(s1 + LEN(sp3), e$, sp3)
                                ELSE
                                    s2 = 0
                                END IF

                                IF s2 THEN
                                    s3 = INSTR(s2 + LEN(sp3), e$, sp3)
                                ELSE
                                    s3 = 0
                                END IF

                                IF s3 = 0 THEN Give_Error "Expected arrayname()": EXIT FUNCTION

                                member_element_id = VAL(MID$(e$, s2 + LEN(sp3), s3 - s2 - LEN(sp3)))
                                o$ = MID$(e$, s3 + LEN(sp3))

                                IF member_element_id > 0 THEN
                                    IF udtearrayelements(member_element_id) = 0 THEN Give_Error "Expected arrayname()": EXIT FUNCTION
                                    ' whole TYPE member-array reference; storage mode is resolved from member metadata
                                ELSEIF LEFT$(o$, 4) = "(0)*" OR LEFT$(o$, 5) = "((0)*" THEN
                                    ' classic whole UDT array reference
                                ELSE
                                    Give_Error "Expected arrayname()": EXIT FUNCTION
                                END IF

                            END IF

                            idnum = VAL(LEFT$(e$, INSTR(e$, sp3) - 1))
                            getid idnum
                            IF Error_Happened THEN EXIT FUNCTION

                            IF targettyp AND ISFIXEDLENGTH THEN
                                targettypsize = CVL(MID$(id2.argsize, curarg * 4 - 4 + 1, 4))
                                source_fixed_size = id.tsize
                                IF member_element_id > 0 THEN source_fixed_size = udtetypesize(member_element_id)
                                IF source_fixed_size <> targettypsize THEN Give_Error "Incorrect array type passed to function": EXIT FUNCTION
                            END IF

                            IF MID$(sfcmemargs(targetid), curarg, 1) = CHR$(1) THEN 'cmem required?
                                IF cmemlist(idnum) = 0 THEN
                                    cmemlist(idnum) = 1

                                    recompile = 1
                                END IF
                            END IF



                            source_dims = 0
                            IF member_element_id > 0 THEN
                                source_dims = udtearraydims(member_element_id)
                            ELSEIF id.linkid = 0 THEN
                                source_dims = id.arrayelements
                            END IF

                            IF source_dims > 0 THEN
                                IF nelereq = 0 THEN
                                    nelereq = source_dims
                                    MID$(id2.nelereq, curarg, 1) = CHR$(nelereq)
                                    ids(targetid) = id2
                                ELSEIF source_dims <> nelereq THEN
                                    Give_Error "Passing arrays with a differing number of elements to a SUB/FUNCTION is not supported": EXIT FUNCTION
                                END IF
                            END IF

                            IF member_element_id > 0 THEN
                                member_arg$ = "": member_prep$ = "": member_dims = 0
                                BuildUDTMemberArg e$, member_arg$, member_prep$, member_dims
                                IF Error_Happened THEN EXIT FUNCTION
                                e$ = member_arg$
                                funcargprep$ = funcargprep$ + member_prep$
                            ELSE
                                e$ = refer(e$, sourcetyp, 1)
                                IF Error_Happened THEN EXIT FUNCTION
                            END IF
                            GOTO dontevaluate
                        END IF












                        'note: not an array...

                        'target is not an array

                        IF (targettyp AND ISSTRING) = 0 THEN
                            IF (sourcetyp AND ISREFERENCE) THEN
                                idnum = VAL(LEFT$(e$, INSTR(e$, sp3) - 1)) 'id# of sourcetyp

                                targettyp2 = targettyp: sourcetyp2 = sourcetyp

                                'get info about source/target
                                arr = 0: IF (sourcetyp2 AND ISARRAY) THEN arr = 1
                                passudtelement = 0: IF (targettyp2 AND ISUDT) = 0 AND (sourcetyp2 AND ISUDT) <> 0 THEN passudtelement = 1: sourcetyp2 = sourcetyp2 - ISUDT

                                'remove flags irrelevant for comparison... ISPOINTER,ISREFERENCE,ISINCONVENTIONALMEMORY,ISARRAY
                                targettyp2 = targettyp2 AND (UDTMASK + ISOFFSETINBITS + ISUDT + ISFLOAT + ISSTRING)
                                sourcetyp2 = sourcetyp2 AND (UDTMASK + ISOFFSETINBITS + ISUDT + ISFLOAT + ISSTRING)

                                'compare types
                                IF sourcetyp2 = targettyp2 THEN

                                    IF sourcetyp AND ISUDT THEN
                                        'udt/udt array

                                        'get info
                                        udtrefid = VAL(e$)
                                        getid udtrefid
                                        IF Error_Happened THEN EXIT FUNCTION
                                        udtrefi = INSTR(e$, sp3) 'end of id
                                        udtrefi2 = INSTR(udtrefi + 1, e$, sp3) 'end of u
                                        udtrefu = VAL(MID$(e$, udtrefi + 1, udtrefi2 - udtrefi - 1))
                                        udtrefi3 = INSTR(udtrefi2 + 1, e$, sp3) 'skip e
                                        udtrefe = VAL(MID$(e$, udtrefi2 + 1, udtrefi3 - udtrefi2 - 1))
                                        o$ = RIGHT$(e$, LEN(e$) - udtrefi3)
                                        'note: most of the UDT info above is not required

                                        IF arr THEN
                                            n2$ = scope$ + "ARRAY_UDT_" + RTRIM$(id.n) + "[0]"
                                        ELSE
                                            n2$ = scope$ + "UDT_" + RTRIM$(id.n)
                                        END IF

                                        e$ = "(void*)( ((char*)(" + n2$ + ")) + (" + o$ + ") )"

                                        'convert void* to target type*
                                        IF passudtelement THEN e$ = "(" + typ2ctyp$(targettyp2 + (targettyp AND ISUNSIGNED), "") + "*)" + e$
                                        IF Error_Happened THEN EXIT FUNCTION

                                    ELSE
                                        'not a udt
                                        IF arr THEN
                                            IF (sourcetyp2 AND ISOFFSETINBITS) THEN Give_Error "Cannot pass _BIT array offsets": EXIT FUNCTION
                                            e$ = "(&(" + refer(e$, sourcetyp, 0) + "))"
                                            IF Error_Happened THEN EXIT FUNCTION
                                        ELSE
                                            e$ = refer(e$, sourcetyp, 1)
                                            IF Error_Happened THEN EXIT FUNCTION
                                        END IF

                                        'note: signed/unsigned mismatch requires casting
                                        IF (sourcetyp AND ISUNSIGNED) <> (targettyp AND ISUNSIGNED) THEN
                                            e$ = "(" + typ2ctyp$(targettyp2 + (targettyp AND ISUNSIGNED), "") + "*)" + e$
                                            IF Error_Happened THEN EXIT FUNCTION
                                        END IF

                                    END IF 'udt?

                                    'force recompile if target needs to be in cmem and the source is not
                                    IF MID$(sfcmemargs(targetid), curarg, 1) = CHR$(1) THEN 'cmem required?
                                        IF cmemlist(idnum) = 0 THEN
                                            cmemlist(idnum) = 1
                                            recompile = 1
                                        END IF
                                    END IF

                                    GOTO dontevaluate
                                END IF 'similar

                                'IF sourcetyp2 = targettyp2 THEN
                                'IF arr THEN
                                'IF (sourcetyp2 AND ISOFFSETINBITS) THEN Give_Error "Cannot pass _BIT array offsets yet": EXIT FUNCTION
                                'e$ = "(&(" + refer(e$, sourcetyp, 0) + "))"
                                'ELSE
                                'e$ = refer(e$, sourcetyp, 1)
                                'END IF
                                'GOTO dontevaluate
                                'END IF

                            END IF 'source is a reference

                        ELSE 'string
                            'it's a string

                            IF (sourcetyp AND ISREFERENCE) THEN
                                idnum = VAL(LEFT$(e$, INSTR(e$, sp3) - 1)) 'id# of sourcetyp
                                IF MID$(sfcmemargs(targetid), curarg, 1) = CHR$(1) THEN 'cmem required?
                                    IF cmemlist(idnum) = 0 THEN
                                        cmemlist(idnum) = 1
                                        recompile = 1
                                    END IF
                                END IF
                            END IF 'reference

                        END IF 'string

                    END IF 'dereference was not used
                END IF 'pointer


                'note: Target is not a pointer...

                'IF (targettyp AND ISSTRING) = 0 THEN
                'IF (sourcetyp AND ISREFERENCE) THEN
                'targettyp2 = targettyp: sourcetyp2 = sourcetyp - ISREFERENCE
                'IF (sourcetyp2 AND ISINCONVENTIONALMEMORY) THEN sourcetyp2 = sourcetyp2 - ISINCONVENTIONALMEMORY
                'IF sourcetyp2 = targettyp2 THEN e$ = refer(e$, sourcetyp, 1): GOTO dontevaluate
                'END IF
                'END IF
                'END IF

                'String-numeric mismatch?
                IF targettyp AND ISSTRING THEN
                    IF (sourcetyp AND ISSTRING) = 0 THEN
                        nth = curarg
                        IF skipFirstArg THEN nth = nth - 1
                        IF ids(targetid).args = 1 THEN Give_Error "String required for function": EXIT FUNCTION
                        Give_Error str_nth$(nth) + " function argument requires a string": EXIT FUNCTION
                    END IF
                END IF
                IF (targettyp AND ISSTRING) = 0 THEN
                    IF sourcetyp AND ISSTRING THEN
                        nth = curarg
                        IF skipFirstArg THEN nth = nth - 1
                        IF ids(targetid).args = 1 THEN Give_Error "Number required for function": EXIT FUNCTION
                        Give_Error str_nth$(nth) + " function argument requires a number": EXIT FUNCTION
                    END IF
                END IF

                'change to "non-pointer" value
                IF (sourcetyp AND ISREFERENCE) THEN
                    e$ = refer(e$, sourcetyp, 0)
                    IF Error_Happened THEN EXIT FUNCTION
                END IF

                IF explicitreference = 0 THEN
                    IF targettyp AND ISUDT THEN
                        nth = curarg
                        IF skipFirstArg THEN nth = nth - 1
                        x$ = "'" + RTRIM$(udtxcname(targettyp AND UDTMASK)) + "'"
                        IF ids(targetid).args = 1 THEN Give_Error "TYPE " + x$ + " required for function": EXIT FUNCTION
                        Give_Error str_nth$(nth) + " function argument requires TYPE " + x$: EXIT FUNCTION
                    END IF
                ELSE
                    IF sourcetyp AND ISUDT THEN Give_Error "Number required for function": EXIT FUNCTION
                END IF

                'round to integer if required
                IF (sourcetyp AND ISFLOAT) THEN
                    IF (targettyp AND ISFLOAT) = 0 THEN
                        '**32 rounding fix
                        bits = targettyp AND UDTMASK
                        IF bits <= 16 THEN e$ = "qbr_float_to_long(" + e$ + ")"
                        IF bits > 16 AND bits < 32 THEN e$ = "qbr_double_to_long(" + e$ + ")"
                        IF bits >= 32 THEN e$ = "qbr(" + e$ + ")"
                    END IF
                END IF

                IF explicitreference THEN
                    IF (targettyp AND ISOFFSETINBITS) THEN
                        'integer value can fit inside int64
                        e$ = "(int64)(" + e$ + ")"
                    ELSE
                        IF (targettyp AND ISFLOAT) THEN
                            IF (targettyp AND UDTMASK) = 32 THEN e$ = "(float)(" + e$ + ")"
                            IF (targettyp AND UDTMASK) = 64 THEN e$ = "(double)(" + e$ + ")"
                            IF (targettyp AND UDTMASK) = 256 THEN e$ = "(long double)(" + e$ + ")"
                        ELSE
                            IF (targettyp AND ISUNSIGNED) THEN
                                IF (targettyp AND UDTMASK) = 8 THEN e$ = "(uint8)(" + e$ + ")"
                                IF (targettyp AND UDTMASK) = 16 THEN e$ = "(uint16)(" + e$ + ")"
                                IF (targettyp AND UDTMASK) = 32 THEN e$ = "(uint32)(" + e$ + ")"
                                IF (targettyp AND UDTMASK) = 64 THEN e$ = "(uint64)(" + e$ + ")"
                            ELSE
                                IF (targettyp AND UDTMASK) = 8 THEN e$ = "(int8)(" + e$ + ")"
                                IF (targettyp AND UDTMASK) = 16 THEN e$ = "(int16)(" + e$ + ")"
                                IF (targettyp AND UDTMASK) = 32 THEN e$ = "(int32)(" + e$ + ")"
                                IF (targettyp AND UDTMASK) = 64 THEN e$ = "(int64)(" + e$ + ")"
                            END IF
                        END IF 'float?
                    END IF 'offset in bits?
                END IF 'explicit?


                IF (targettyp AND ISPOINTER) THEN 'pointer required
                    IF (targettyp AND ISSTRING) THEN GOTO dontevaluate 'no changes required
                    '20090703
                    t$ = typ2ctyp$(targettyp, "")
                    IF Error_Happened THEN EXIT FUNCTION
                    v$ = "pass" + _TOSTR$(uniquenumber)
                    'assume numeric type
                    IF MID$(sfcmemargs(targetid), curarg, 1) = CHR$(1) THEN 'cmem required?
                        bytesreq = ((targettyp AND UDTMASK) + 7) \ 8
                        WriteBufLine defdatahandle, t$ + " *" + v$ + "=NULL;"
                        WriteBufLine DataTxtBuf, "if(" + v$ + "==NULL){"
                        WriteBufLine DataTxtBuf, "cmem_sp-=" + _TOSTR$(bytesreq) + ";"
                        WriteBufLine DataTxtBuf, v$ + "=(" + t$ + "*)(dblock+cmem_sp);"
                        WriteBufLine DataTxtBuf, "if (cmem_sp<qbs_cmem_sp) error(257);"
                        WriteBufLine DataTxtBuf, "}"
                        e$ = "&(*" + v$ + "=" + e$ + ")"
                    ELSE
                        WriteBufLine DataTxtBuf, t$ + " " + v$ + ";"
                        e$ = "&(" + v$ + "=" + e$ + ")"
                    END IF
                    GOTO dontevaluate
                END IF

                dontevaluate:

                IF id2.ccall THEN

                    'if a forced cast from a returned ccall function is in e$, remove it
                    IF LEFT$(e$, 3) = "(  " THEN
                        e$ = removecast$(e$)
                    END IF

                    IF targettyp AND ISSTRING THEN
                        e$ = "(char*)(" + e$ + ")->chr"
                    END IF

                    IF LTRIM$(RTRIM$(e$)) = "0" THEN e$ = "NULL"

                END IF

                r$ = r$ + e$

                '***special case****
                IF n$ = "_MEM" THEN
                    IF args = 1 THEN
                        IF curarg = 1 THEN r$ = r$ + ")": GOTO evalfuncspecial
                    END IF
                    IF args = 2 THEN
                        IF curarg = 2 THEN r$ = r$ + ")": GOTO evalfuncspecial
                    END IF
                END IF

                IF i <> n AND noComma = 0 THEN r$ = r$ + ","
                noComma = 0
                firsti = i + 1
                curarg = curarg + 1
            END IF
        NEXT

        ' Add on any extra optional arguments that were not provided
        '
        ' Overloaded functions do not require the omitted arguments to be provided
        IF curarg <= id2.args AND NOT id2.overloaded THEN
            FOR i = curarg TO id2.args
                IF i = 1 THEN r$ = r$ + "NULL" ELSE r$ = r$ + ",NULL"
            NEXT
        END IF
    END IF

    IF n$ = "UBOUND" OR n$ = "LBOUND" THEN
        IF r$ = ",NULL" THEN r$ = ",1" ' FIXME: ??????
        dim_expr$ = MID$(r$, 2)

        ' Use the TYPE-member bound path only when the first argument was parsed as a whole
        ' member array. Inline members read declaration metadata; explicit _Dynamic members read
        ' their live descriptor. Classic arrays continue through func_ubound/func_lbound below.
        IF ulboundarrayisnested THEN
            s1 = INSTR(ulboundarray$, sp3)
            IF s1 THEN s2 = INSTR(s1 + LEN(sp3), ulboundarray$, sp3) ELSE s2 = 0
            IF s2 THEN
                s3 = INSTR(s2 + LEN(sp3), ulboundarray$, sp3)
            ELSE
                s3 = 0
            END IF

            IF s3 = 0 THEN Give_Error "Expected array-name": EXIT FUNCTION

            ulboundid = VAL(LEFT$(ulboundarray$, s1 - 1))
            epos1 = s2 + LEN(sp3)
            epos2 = s3 - 1
            member_element_id = VAL(MID$(ulboundarray$, epos1, epos2 - epos1 + 1))
            IF udtearrayelements(member_element_id) = 0 THEN Give_Error "Expected array-name": EXIT FUNCTION

            getid ulboundid
            IF Error_Happened THEN EXIT FUNCTION
            IF id.dynudt AND UDTMemberDynDesc%(member_element_id) THEN ulboundarrayisdyn = -1 ELSE ulboundarrayisdyn = 0

            IF ulboundarrayisdyn THEN
                ulboundoffset = MID$(ulboundarray$, s3 + LEN(sp3))
                ulboundbase = RTRIM$(id.callname)
                IF id.arraytype THEN ulboundbase = ulboundbase + "[0]"
                ulbounddesc = "(*((ptrszint**)(((char*)" + ulboundbase + ")+(" + ulboundoffset + "))))"
                IF n$ = "UBOUND" THEN
                    r$ = UDTDynArrayBoundExpr$(ulbounddesc, dim_expr$, -1)
                ELSE
                    r$ = UDTDynArrayBoundExpr$(ulbounddesc, dim_expr$, 0)
                END IF
            ELSE
                IF n$ = "UBOUND" THEN
                    r$ = UDTArrayBoundExpr$(udtearraydesc(member_element_id), udtearraydims(member_element_id), dim_expr$, -1)
                ELSE
                    r$ = UDTArrayBoundExpr$(udtearraydesc(member_element_id), udtearraydims(member_element_id), dim_expr$, 0)
                END IF
            END IF
            IF Error_Happened THEN EXIT FUNCTION

            typ& = INTEGER64TYPE - ISPOINTER
            GOTO evalfuncspecial
        END IF

        IF n$ = "UBOUND" THEN r2$ = "func_ubound(" ELSE r2$ = "func_lbound("
        e$ = refer$(ulboundarray$, sourcetyp, 1)
        IF Error_Happened THEN EXIT FUNCTION
        'note: ID contains refer'ed array info

        arrayelements = id.arrayelements '2009
        IF arrayelements = -1 THEN arrayelements = 1 '2009


        r$ = r2$ + e$ + r$ + "," + _TOSTR$(arrayelements) + ")"
        typ& = INTEGER64TYPE - ISPOINTER
        GOTO evalfuncspecial
    END IF

    IF passomit THEN
        r$ = r$ + ",0"

        IF hasOptionalFirstArg THEN
            IF providedArgs(1) THEN r$ = r$ + "|1"
        ELSE
            FOR i = firstOptionalArgument TO UBOUND(providedArgs)
                IF providedArgs(i) THEN r$ = r$ + "|" + _TOSTR$(_SHL(1, i - firstOptionalArgument))
            NEXT
        END IF
    END IF
    r$ = r$ + ")"
    IF funcargprep$ <> "" THEN r$ = "([&](){" + funcargprep$ + "return " + r$ + ";})()"

    evalfuncspecial:

    IF n$ = "ABS" THEN typ& = sourcetyp 'ABS Note: ABS() returns argument #1's type

    'QB-like conversion of math functions returning floating point values
    IF n$ = "SIN" OR n$ = "COS" OR n$ = "TAN" OR n$ = "ATN" OR n$ = "SQR" OR n$ = "LOG" THEN
        b = sourcetyp AND UDTMASK
        IF sourcetyp AND ISFLOAT THEN
            'Default is FLOATTYPE
            IF b = 64 THEN typ& = DOUBLETYPE - ISPOINTER
            IF b = 32 THEN typ& = SINGLETYPE - ISPOINTER
        ELSE
            'Default is FLOATTYPE
            IF b <= 32 THEN typ& = DOUBLETYPE - ISPOINTER
            IF b <= 16 THEN typ& = SINGLETYPE - ISPOINTER
        END IF
    END IF

    IF id2.ret = ISUDT + (1) THEN
        '***special case***
        v$ = "func" + _TOSTR$(uniquenumber)
        WriteBufLine defdatahandle, "mem_block " + v$ + ";"
        r$ = "(" + v$ + "=" + r$ + ")"
    END IF

    IF id2.ccall THEN
        IF LEFT$(r$, 11) = "(  char*  )" THEN
            r$ = "qbs_new_txt(" + r$ + ")"
        END IF
    END IF

    IF Debug THEN PRINT #9, "evaluatefunc:out:"; r$
    evaluatefunc$ = r$
END FUNCTION

FUNCTION variablesize$ (i AS LONG) 'ID or -1 (if ID already 'loaded')
    'Note: assumes whole bytes, no bit offsets/sizes
    IF i <> -1 THEN getid i
    IF Error_Happened THEN EXIT FUNCTION
    'find base size from type
    t = id.t: IF t = 0 THEN t = id.arraytype
    bytes = (t AND UDTMASK) \ 8

    IF t AND ISUDT THEN 'correct size for UDTs
        u = t AND UDTMASK
        bytes = udtxsize(u) \ 8
        IF id.dynudt THEN bytes = UDTDynLayoutSize&(u) \ 8
    END IF

    IF t AND ISSTRING THEN 'correct size for strings
        IF t AND ISFIXEDLENGTH THEN
            bytes = id.tsize
        ELSE
            IF id.arraytype THEN Give_Error "Cannot determine size of variable-length string array": EXIT FUNCTION
            variablesize$ = scope$ + "STRING_" + RTRIM$(id.n) + "->len"
            EXIT FUNCTION
        END IF
    END IF

    IF id.arraytype THEN 'multiply size for arrays
        n$ = RTRIM$(id.callname)
        s$ = _TOSTR$(bytes) + "*(" + n$ + "[2]&1)" 'note: multiplying by 0 if array not currently defined (affects dynamic arrays)
        arrayelements = id.arrayelements: IF arrayelements = -1 THEN arrayelements = 1 '2009
        FOR i2 = 1 TO arrayelements
            s$ = s$ + "*" + n$ + "[" + _TOSTR$(i2 * 4 - 4 + 5) + "]"
        NEXT
        variablesize$ = "(" + s$ + ")"
        EXIT FUNCTION
    END IF

    variablesize$ = _TOSTR$(bytes)
END FUNCTION



FUNCTION evaluatetotyp$ (a2$, targettyp AS LONG)
    'note: 'evaluatetotyp' no longer performs 'fixoperationorder' on a2$ (in many cases, this has already been done)

    DIM AS LONG member_element_id, final_member_array_indexed, elem_typ 'member_element_id indexes TYPE member-array metadata
    DIM AS STRING desc_expr
    DIM udtElem AS LONG

    a$ = a2$

    dynmemlockexpr = ""
    allow_bare_member_array = 0
    ' Address/size/_MEM helper requests may need a whole TYPE member-array reference. The
    ' resulting metadata later selects inline storage (unmarked/_Static) or an explicit _Dynamic
    ' descriptor. Enable this parser mode only for those target types so ordinary expressions
    ' still require an element index.
    IF targettyp = -2 OR targettyp = -4 OR targettyp = -5 OR targettyp = -6 OR targettyp = -7 OR targettyp = -8 THEN
        allow_bare_member_array = -1
    END IF

    final_member_array_indexed = 0 'whole-member-array versus indexed-final-member bookkeeping
    IF targettyp = -4 OR targettyp = -5 OR targettyp = -6 OR targettyp = -7 OR targettyp = -8 THEN
        final_member_array_indexed = HasIndexedFinalMemberArray%(a$)
    END IF


    IF allow_bare_member_array THEN udt_allow_bare_array = -1
    e$ = evaluate(a$, sourcetyp)
    IF allow_bare_member_array THEN udt_allow_bare_array = 0
    IF Error_Happened THEN EXIT FUNCTION

    '-5 size
    '-6 offset
    IF targettyp = -4 OR targettyp = -5 OR targettyp = -6 THEN '? -> byte_element(offset,element size in bytes)
        IF (sourcetyp AND ISREFERENCE) = 0 THEN Give_Error "Expected variable name/array element": EXIT FUNCTION
        IF (sourcetyp AND ISOFFSETINBITS) THEN Give_Error "Variable/element cannot be _BIT aligned": EXIT FUNCTION

        ' print "-4: evaluated as ["+e$+"]":sleep 1

        ' Whole inline TYPE member arrays (unmarked or _Static) carry ISARRAY plus element type flags (often ISUDT).
        ' Detect that encoded id|parentUDT|memberElement|byteOffset form before the generic UDT branch so
        ' LEN/_OFFSET and related helpers operate on the full inline array block instead of one element.
        IF (sourcetyp AND ISARRAY) THEN
            s1 = INSTR(e$, sp3)
            IF s1 THEN s2 = INSTR(s1 + LEN(sp3), e$, sp3) ELSE s2 = 0
            IF s2 THEN s3 = INSTR(s2 + LEN(sp3), e$, sp3) ELSE s3 = 0
            IF s3 THEN
                idnumber = VAL(LEFT$(e$, s1 - 1))
                u = VAL(MID$(e$, s1 + LEN(sp3), s2 - s1 - LEN(sp3)))
                member_element_id = VAL(MID$(e$, s2 + LEN(sp3), s3 - s2 - LEN(sp3)))
                IF member_element_id > 0 AND final_member_array_indexed = 0 THEN
                    IF udtearrayelements(member_element_id) THEN
                        o$ = MID$(e$, s3 + LEN(sp3))
                        getid idnumber
                        IF Error_Happened THEN EXIT FUNCTION
                        n$ = "UDT_" + RTRIM$(id.n)
                        IF id.arraytype THEN n$ = "ARRAY_" + n$ + "[0]"
                        IF id.dynudt AND UDTMemberDynDesc%(member_element_id) THEN
                            desc_expr = "(*((ptrszint**)(((char*)" + scope$ + n$ + ")+(" + o$ + "))))"
                            desc_expr = UDTDynArrayDescGuard$(desc_expr, udtearraydims(member_element_id))
                            IF Error_Happened THEN EXIT FUNCTION
                            elem_bytes = udt_dyn_array_elem_bytes(member_element_id)
                            bytes$ = UDTDynArrayBytesExpr$(desc_expr, elem_bytes)
                            IF Error_Happened THEN EXIT FUNCTION
                            dst$ = "((char*)" + desc_expr + "[0])"
                            evaluatetotyp$ = "byte_element((uint64)" + dst$ + "," + bytes$ + "," + NewByteElement$ + ")"
                            IF targettyp = -5 THEN evaluatetotyp$ = bytes$
                            IF targettyp = -6 THEN evaluatetotyp$ = dst$
                            EXIT FUNCTION
                        END IF
                        dst$ = "(((char*)" + scope$ + n$ + ")+(" + o$ + "))"
                        bytes$ = _TOSTR$(udtesize(member_element_id) \ 8)
                        evaluatetotyp$ = "byte_element((uint64)" + dst$ + "," + bytes$ + "," + NewByteElement$ + ")"
                        IF targettyp = -5 THEN evaluatetotyp$ = bytes$
                        IF targettyp = -6 THEN evaluatetotyp$ = dst$
                        EXIT FUNCTION
                    END IF
                END IF
            END IF
        END IF

        IF (sourcetyp AND ISUDT) THEN 'User Defined Type -> byte_element(offset,bytes)
            IF udtxvariable(sourcetyp AND UDTMASK) THEN Give_Error "UDT must have fixed size": EXIT FUNCTION
            idnumber = VAL(e$)
            i = INSTR(e$, sp3): e$ = RIGHT$(e$, LEN(e$) - i)
            u = VAL(e$) 'closest parent
            i = INSTR(e$, sp3): e$ = RIGHT$(e$, LEN(e$) - i)
            udtElem = VAL(e$)
            i = INSTR(e$, sp3): e$ = RIGHT$(e$, LEN(e$) - i)
            o$ = e$
            getid idnumber
            IF Error_Happened THEN EXIT FUNCTION
            ' A whole descriptor-owning UDT element contains pointers/qbs ownership, not a flat
            ' user payload. Exposing it through _MEM would hand out raw descriptor addresses and
            ' make later REDIM/ERASE invalidation impossible, so only fixed-size submembers pass.
            IF udtElem = 0 AND id.dynudt AND UDTDynHasMemberArrays%(u, id.dynudtmode) THEN Give_Error "_MEM cannot reference a TYPE value that contains explicit _Dynamic member arrays": EXIT FUNCTION
            IF udtElem = 0 AND id.dynudt AND udtxvariable(u) THEN Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION
            IF udtElem = 0 AND id.arraytype <> 0 THEN
                IF udtxvariable(u) THEN
                    IF UDTDynHasMemberArrays%(u, 1) THEN Give_Error "_MEM cannot reference a TYPE value that contains explicit _Dynamic member arrays": EXIT FUNCTION
                END IF
            END IF
            n$ = "UDT_" + RTRIM$(id.n)
            IF id.arraytype THEN
                n$ = "ARRAY_" + n$ + "[0]"
                'whole array reference examplename()?
                IF LEFT$(o$, 5) = "((0)*" THEN 'LEN for nested array size - without this returned size for whole array is size for 1 element
                    'use -2 type method
                    GOTO method2usealludt
                END IF
            END IF

            dst$ = "(((char*)" + scope$ + n$ + ")+(" + o$ + "))"

            'determine size of element
            IF udtElem = 0 THEN 'no specific element, use size of entire type
                IF id.dynudt THEN
                    bytes$ = _TOSTR$(UDTDynLayoutSize&(u) \ 8)
                ELSE
                    bytes$ = _TOSTR$(udtxsize(u) \ 8)
                END IF
            ELSE 'a specific element
                IF (udtetype(udtElem) AND ISSTRING) > 0 AND (udtetype(udtElem) AND ISFIXEDLENGTH) = 0 AND (targettyp = -5) THEN
                    evaluatetotyp$ = "(*(qbs**)" + dst$ + ")->len"
                    EXIT FUNCTION
                ELSEIF (udtetype(udtElem) AND ISSTRING) > 0 AND (udtetype(udtElem) AND ISFIXEDLENGTH) = 0 AND (targettyp = -4) THEN
                    dst$ = "(*((qbs**)((char*)" + scope$ + n$ + "+(" + o$ + "))))->chr"
                    bytes$ = "(*((qbs**)((char*)" + scope$ + n$ + "+(" + o$ + "))))->len"
                    evaluatetotyp$ = "byte_element((uint64)" + dst$ + "," + bytes$ + "," + NewByteElement$ + ")"
                    EXIT FUNCTION
                END IF
                IF udtearrayelements(udtElem) THEN
                    bytes$ = _TOSTR$(udt_array_member_bytes(udtElem))
                ELSE
                    bytes$ = _TOSTR$(udtesize(udtElem) \ 8)
                END IF
            END IF
            evaluatetotyp$ = "byte_element((uint64)" + dst$ + "," + bytes$ + "," + NewByteElement$ + ")"
            IF targettyp = -5 THEN evaluatetotyp$ = bytes$
            IF targettyp = -6 THEN evaluatetotyp$ = dst$
            EXIT FUNCTION
        END IF

        IF (sourcetyp AND ISARRAY) THEN 'Array reference -> byte_element(offset,bytes)
            ' A bare inline TYPE member array is encoded as id|udt|element|byteoffset rather than the
            ' classic id|index form used by normal arrays. Recover the address and size of the whole inline
            ' block directly from the matched UDT element metadata.
            s1 = INSTR(e$, sp3)
            IF s1 THEN s2 = INSTR(s1 + LEN(sp3), e$, sp3) ELSE s2 = 0
            IF s2 THEN s3 = INSTR(s2 + LEN(sp3), e$, sp3) ELSE s3 = 0
            IF s3 THEN
                idnumber = VAL(LEFT$(e$, s1 - 1))
                u = VAL(MID$(e$, s1 + LEN(sp3), s2 - s1 - LEN(sp3)))
                member_element_id = VAL(MID$(e$, s2 + LEN(sp3), s3 - s2 - LEN(sp3)))
                IF member_element_id > 0 AND final_member_array_indexed = 0 THEN 'conditions for PARENT nested Arrays

                    ' Whole inline TYPE member array: use the member block from the encoded
                    ' UDT reference instead of the generic parent-UDT path.
                    IF udtearrayelements(member_element_id) THEN
                        o$ = MID$(e$, s3 + LEN(sp3))
                        getid idnumber
                        IF Error_Happened THEN EXIT FUNCTION
                        n$ = "UDT_" + RTRIM$(id.n)
                        IF id.arraytype THEN n$ = "ARRAY_" + n$ + "[0]"
                        IF id.dynudt AND UDTMemberDynDesc%(member_element_id) THEN
                            desc_expr = "(*((ptrszint**)(((char*)" + scope$ + n$ + ")+(" + o$ + "))))"
                            desc_expr = UDTDynArrayDescGuard$(desc_expr, udtearraydims(member_element_id))
                            IF Error_Happened THEN EXIT FUNCTION
                            elem_bytes = udt_dyn_array_elem_bytes(member_element_id)
                            bytes$ = UDTDynArrayBytesExpr$(desc_expr, elem_bytes)
                            IF Error_Happened THEN EXIT FUNCTION
                            dst$ = "((char*)" + desc_expr + "[0])"
                            evaluatetotyp$ = "byte_element((uint64)" + dst$ + "," + bytes$ + "," + NewByteElement$ + ")"
                            IF targettyp = -5 THEN evaluatetotyp$ = bytes$
                            IF targettyp = -6 THEN evaluatetotyp$ = dst$
                            EXIT FUNCTION
                        END IF
                        dst$ = "(((char*)" + scope$ + n$ + ")+(" + o$ + "))"
                        bytes$ = _TOSTR$(udtesize(member_element_id) \ 8)
                        evaluatetotyp$ = "byte_element((uint64)" + dst$ + "," + bytes$ + "," + NewByteElement$ + ")"
                        IF targettyp = -5 THEN evaluatetotyp$ = bytes$
                        IF targettyp = -6 THEN evaluatetotyp$ = dst$
                        EXIT FUNCTION
                    END IF
                END IF
            END IF

            'whole array reference examplename()?
            IF RIGHT$(e$, 2) = sp3 + "0" THEN
                'use -2 type method
                IF sourcetyp AND ISSTRING THEN
                    IF (sourcetyp AND ISFIXEDLENGTH) = 0 THEN
                        Give_Error "Cannot pass array of variable-length strings": EXIT FUNCTION
                    END IF
                END IF
                GOTO method2useall
            END IF
            'assume a specific element
            IF sourcetyp AND ISSTRING THEN
                IF sourcetyp AND ISFIXEDLENGTH THEN
                    idnumber = VAL(e$)
                    getid idnumber
                    IF Error_Happened THEN EXIT FUNCTION
                    bytes$ = _TOSTR$(id.tsize)
                    e$ = refer(e$, sourcetyp, 0)
                    IF Error_Happened THEN EXIT FUNCTION
                    evaluatetotyp$ = "byte_element((uint64)" + e$ + "->chr," + bytes$ + "," + NewByteElement$ + ")"
                    IF targettyp = -5 THEN evaluatetotyp$ = bytes$
                    IF targettyp = -6 THEN evaluatetotyp$ = e$ + "->chr"
                ELSE
                    e$ = refer(e$, sourcetyp, 0)
                    IF Error_Happened THEN EXIT FUNCTION

                    evaluatetotyp$ = "byte_element((uint64)" + e$ + "->chr," + e$ + "->len," + NewByteElement$ + ")"
                    IF targettyp = -5 THEN evaluatetotyp$ = e$ + "->len"
                    IF targettyp = -6 THEN evaluatetotyp$ = e$ + "->chr"
                END IF
                EXIT FUNCTION
            END IF
            e$ = refer(e$, sourcetyp, 0)
            IF Error_Happened THEN EXIT FUNCTION
            e$ = "(&(" + e$ + "))"
            bytes$ = _TOSTR$((sourcetyp AND UDTMASK) \ 8)
            evaluatetotyp$ = "byte_element((uint64)" + e$ + "," + bytes$ + "," + NewByteElement$ + ")"
            IF targettyp = -5 THEN evaluatetotyp$ = bytes$
            IF targettyp = -6 THEN evaluatetotyp$ = e$
            EXIT FUNCTION
        END IF

        IF sourcetyp AND ISSTRING THEN 'String -> byte_element(offset,bytes)
            IF sourcetyp AND ISFIXEDLENGTH THEN
                idnumber = VAL(e$)
                getid idnumber
                IF Error_Happened THEN EXIT FUNCTION
                bytes$ = _TOSTR$(id.tsize)
                e$ = refer(e$, sourcetyp, 0)
                IF Error_Happened THEN EXIT FUNCTION
            ELSE
                e$ = refer(e$, sourcetyp, 0)
                IF Error_Happened THEN EXIT FUNCTION
                bytes$ = e$ + "->len"
            END IF
            evaluatetotyp$ = "byte_element((uint64)" + e$ + "->chr," + bytes$ + "," + NewByteElement$ + ")"
            IF targettyp = -5 THEN evaluatetotyp$ = bytes$
            IF targettyp = -6 THEN evaluatetotyp$ = e$ + "->chr"
            EXIT FUNCTION
        END IF

        'Standard variable -> byte_element(offset,bytes)
        e$ = refer(e$, sourcetyp, 1) 'get the variable's formal name
        IF Error_Happened THEN EXIT FUNCTION
        size = (sourcetyp AND UDTMASK) \ 8 'calculate its size in bytes
        evaluatetotyp$ = "byte_element((uint64)" + e$ + "," + _TOSTR$(size) + "," + NewByteElement$ + ")"
        IF targettyp = -5 THEN evaluatetotyp$ = _TOSTR$(size)
        IF targettyp = -6 THEN evaluatetotyp$ = e$
        EXIT FUNCTION

    END IF '-4, -5, -6




    IF targettyp = -8 THEN '? -> _MEM structure helper {offset, fullsize, typeval, elementsize, sf_mem_lock|???}
        IF (sourcetyp AND ISREFERENCE) = 0 THEN Give_Error "Expected variable name/array element": EXIT FUNCTION
        IF (sourcetyp AND ISOFFSETINBITS) THEN Give_Error "Variable/element cannot be _BIT aligned": EXIT FUNCTION


        ' Whole inline TYPE member arrays must be recognized before the generic UDT path.
        ' Their encoded reference has the form id|parentUDT|memberElement|byteOffset and represents
        ' the entire inline member array rather than the tail of the parent UDT.
        s1 = INSTR(e$, sp3)
        IF s1 THEN s2 = INSTR(s1 + LEN(sp3), e$, sp3) ELSE s2 = 0
        IF s2 THEN s3 = INSTR(s2 + LEN(sp3), e$, sp3) ELSE s3 = 0

        IF s3 <> 0 AND final_member_array_indexed THEN
            idnumber = VAL(LEFT$(e$, s1 - 1))
            u = VAL(MID$(e$, s1 + LEN(sp3), s2 - s1 - LEN(sp3)))
            member_element_id = VAL(MID$(e$, s2 + LEN(sp3), s3 - s2 - LEN(sp3)))

            IF member_element_id > 0 THEN
                IF udtearrayelements(member_element_id) THEN
                    getid idnumber
                    IF Error_Happened THEN EXIT FUNCTION
                    n$ = "UDT_" + RTRIM$(id.n)
                    IF id.arraytype THEN n$ = "ARRAY_" + n$ + "[0]"
                    IF id.dynudt AND UDTMemberDynDesc%(member_element_id) THEN
                        IF DynMemVarStr%(member_element_id) THEN Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION
                        IF DynMemUDTVarStr%(member_element_id) THEN Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION
                        o$ = MID$(e$, s3 + LEN(sp3))
                        elem_bytes = udt_dyn_array_elem_bytes(member_element_id)
                        dst$ = "(((char*)" + scope$ + n$ + ")+(" + o$ + "))"
                        elem_typ = udtetype(member_element_id)
                        t = Type2MemTypeValue(elem_typ)
                        IF dynmemlockexpr = "" THEN Give_Error "_MEM cannot access this explicit _Dynamic TYPE member array": EXIT FUNCTION
                        evaluatetotyp$ = "(ptrszint)" + dst$ + "," + _TOSTR$(elem_bytes) + "," + _TOSTR$(t) + "," + _TOSTR$(elem_bytes) + "," + dynmemlockexpr
                        EXIT FUNCTION
                    END IF
                END IF
            END IF
        END IF

        IF ((sourcetyp AND ISARRAY) <> 0) AND (s3 <> 0) THEN

            IF sourcetyp AND ISSTRING THEN
                IF (sourcetyp AND ISFIXEDLENGTH) = 0 THEN
                    Give_Error "Cannot pass array of variable-length strings": EXIT FUNCTION
                END IF
            END IF
            idnumber = VAL(LEFT$(e$, s1 - 1))
            u = VAL(MID$(e$, s1 + LEN(sp3), s2 - s1 - LEN(sp3)))
            member_element_id = VAL(MID$(e$, s2 + LEN(sp3), s3 - s2 - LEN(sp3)))

            ' Whole inline TYPE member array: build the _MEM descriptor from the inline
            ' member block so the member array gets its own correct memory view.
            IF member_element_id > 0 THEN
                IF udtearrayelements(member_element_id) THEN
                    o$ = MID$(e$, s3 + LEN(sp3))
                    getid idnumber
                    IF Error_Happened THEN EXIT FUNCTION
                    n$ = "UDT_" + RTRIM$(id.n)
                    IF id.arraytype THEN n$ = "ARRAY_" + n$ + "[0]"
                    IF id.dynudt AND UDTMemberDynDesc%(member_element_id) AND final_member_array_indexed THEN
                        IF DynMemVarStr%(member_element_id) THEN Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION
                        IF DynMemUDTVarStr%(member_element_id) THEN Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION
                        ' Indexed element of a descriptor-backed TYPE member array, e.g. _MEM(ff(3).b(10)).
                        ' The encoded offset o$ already points at the selected element. Do not re-evaluate
                        ' ff(3).b() here; that path can fall back into the bare-member parser guard and raise
                        ' "Expected array index". This branch returns a one-element memory view.
                        elem_bytes = udt_dyn_array_elem_bytes(member_element_id)
                        dst$ = "(((char*)" + scope$ + n$ + ")+(" + o$ + "))"
                        elem_typ = udtetype(member_element_id)
                        t = Type2MemTypeValue(elem_typ)
                        IF dynmemlockexpr = "" THEN Give_Error "_MEM cannot access this explicit _Dynamic TYPE member array": EXIT FUNCTION
                        evaluatetotyp$ = "(ptrszint)" + dst$ + "," + _TOSTR$(elem_bytes) + "," + _TOSTR$(t) + "," + _TOSTR$(elem_bytes) + "," + dynmemlockexpr
                        EXIT FUNCTION
                    END IF
                    IF id.dynudt AND UDTMemberDynDesc%(member_element_id) THEN
                        IF DynMemVarStr%(member_element_id) THEN Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION
                        IF DynMemUDTVarStr%(member_element_id) THEN Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION
                        desc_expr = "(*((ptrszint**)(((char*)" + scope$ + n$ + ")+(" + o$ + "))))"
                        desc_expr = UDTDynArrayDescGuard$(desc_expr, udtearraydims(member_element_id))
                        IF Error_Happened THEN EXIT FUNCTION
                        elem_bytes = udt_dyn_array_elem_bytes(member_element_id)
                        bytes$ = UDTDynArrayBytesExpr$(desc_expr, elem_bytes)
                        IF Error_Happened THEN EXIT FUNCTION
                        dst$ = "((char*)" + desc_expr + "[0])"
                        t = Type2MemTypeValue(sourcetyp)
                        lk$ = "(mem_lock*)(" + desc_expr + "[" + desc_expr + "[3]*4+4])"
                        evaluatetotyp$ = "(ptrszint)" + dst$ + "," + bytes$ + "," + _TOSTR$(t) + "," + _TOSTR$(elem_bytes) + "," + lk$
                        EXIT FUNCTION
                    END IF
                    bytes$ = _TOSTR$(udtesize(member_element_id) \ 8)
                    dst$ = "(((char*)" + scope$ + n$ + ")+(" + o$ + "))"
                    t = Type2MemTypeValue(sourcetyp)
                    evaluatetotyp$ = "(ptrszint)" + dst$ + "," + bytes$ + "," + _TOSTR$(t) + "," + _TOSTR$(udt_array_member_bytes(member_element_id)) + ",sf_mem_lock"
                    EXIT FUNCTION
                END IF
            END IF
        END IF

        IF dynmemlockexpr <> "" AND (sourcetyp AND ISUDT) THEN
            ' Indexed descriptor-backed member arrays carry their own mem_lock. This branch
            ' attaches the returned _MEM block to that descriptor lock instead of sf_mem_lock,
            ' so member REDIM/ERASE invalidates outstanding _MEM views correctly.
            idnumber = VAL(e$)
            i = INSTR(e$, sp3): e$ = RIGHT$(e$, LEN(e$) - i)
            u = VAL(e$)
            i = INSTR(e$, sp3): e$ = RIGHT$(e$, LEN(e$) - i)
            udtElem = VAL(e$)
            i = INSTR(e$, sp3): e$ = RIGHT$(e$, LEN(e$) - i)
            o$ = e$
            getid idnumber
            IF Error_Happened THEN EXIT FUNCTION
            IF udtElem = 0 THEN
                IF udtxvariable(u) THEN Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION
            ELSE
                IF DynMemVarStr%(udtElem) THEN Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION
                IF DynMemUDTVarStr%(udtElem) THEN Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION
            END IF
            n$ = "UDT_" + RTRIM$(id.n)
            IF id.arraytype THEN n$ = "ARRAY_" + n$ + "[0]"
            dst$ = "(((char*)" + scope$ + n$ + ")+(" + o$ + "))"
            IF udtElem = 0 THEN
                elem_bytes = udtxsize(u) \ 8
                IF id.dynudt THEN elem_bytes = UDTDynLayoutSize&(u) \ 8
            ELSE
                elem_bytes = udtesize(udtElem) \ 8
            END IF
            t = Type2MemTypeValue(sourcetyp)
            evaluatetotyp$ = "(ptrszint)" + dst$ + "," + _TOSTR$(elem_bytes) + "," + _TOSTR$(t) + "," + _TOSTR$(elem_bytes) + "," + dynmemlockexpr
            EXIT FUNCTION
        END IF

        IF (sourcetyp AND ISUDT) THEN 'User Defined Type -> byte_element(offset,bytes)
            idnumber = VAL(e$)
            i = INSTR(e$, sp3): e$ = RIGHT$(e$, LEN(e$) - i)
            u = VAL(e$) 'closest parent
            i = INSTR(e$, sp3): e$ = RIGHT$(e$, LEN(e$) - i)
            udtElem = VAL(e$)
            i = INSTR(e$, sp3): e$ = RIGHT$(e$, LEN(e$) - i)
            o$ = e$
            getid idnumber
            IF Error_Happened THEN EXIT FUNCTION
            IF udtElem = 0 AND id.dynudt AND UDTDynHasMemberArrays%(u, id.dynudtmode) THEN Give_Error "_MEM cannot reference a TYPE value that contains explicit _Dynamic member arrays": EXIT FUNCTION
            IF udtElem = 0 AND id.dynudt AND udtxvariable(u) THEN Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION
            n$ = "UDT_" + RTRIM$(id.n)
            IF id.arraytype THEN
                n$ = "ARRAY_" + n$ + "[0]"
                'whole array reference examplename()?
                IF LEFT$(o$, 5) = "((0)*" THEN ' LEN for nested array size - without this returned size for whole array is size for 1 element
                    'use -7 type method
                    GOTO method2usealludt__7
                END IF
            END IF
            'determine size of element
            IF udtElem = 0 THEN 'no specific element, use size of entire type
                IF id.dynudt THEN
                    bytes$ = _TOSTR$(UDTDynLayoutSize&(u) \ 8)
                ELSE
                    bytes$ = _TOSTR$(udtxsize(u) \ 8)
                END IF
                t1 = ISUDT + udtetype(u)
            ELSE 'a specific element
                bytes$ = _TOSTR$(udtesize(udtElem) \ 8)
                t1 = udtetype(udtElem)
            END IF
            dst$ = "(((char*)" + scope$ + n$ + ")+(" + o$ + "))"
            'evaluatetotyp$ = "byte_element((uint64)" + dst$ + "," + bytes$ + "," + NewByteElement$ + ")"
            'IF targettyp = -5 THEN evaluatetotyp$ = bytes$
            'IF targettyp = -6 THEN evaluatetotyp$ = dst$

            t = Type2MemTypeValue(t1)
            evaluatetotyp$ = "(ptrszint)" + dst$ + "," + bytes$ + "," + _TOSTR$(t) + "," + bytes$ + ",sf_mem_lock"

            EXIT FUNCTION
        END IF

        IF (sourcetyp AND ISARRAY) THEN 'Array reference -> byte_element(offset,bytes)
            ' Support whole inline TYPE member arrays in _MEMELEMENT the same way normal whole-array
            ' references are supported: return a mem block that begins at the first inline element.
            s1 = INSTR(e$, sp3)
            IF s1 THEN s2 = INSTR(s1 + LEN(sp3), e$, sp3) ELSE s2 = 0
            IF s2 THEN s3 = INSTR(s2 + LEN(sp3), e$, sp3) ELSE s3 = 0
            IF s3 THEN
                idnumber = VAL(LEFT$(e$, s1 - 1))
                u = VAL(MID$(e$, s1 + LEN(sp3), s2 - s1 - LEN(sp3)))
                member_element_id = VAL(MID$(e$, s2 + LEN(sp3), s3 - s2 - LEN(sp3)))

                'Whole inline TYPE member array: return a mem block that starts at the first
                ' inline element of the member array.
                IF member_element_id > 0 THEN
                    IF udtearrayelements(member_element_id) THEN
                        o$ = MID$(e$, s3 + LEN(sp3))
                        IF sourcetyp AND ISSTRING THEN
                            IF (sourcetyp AND ISFIXEDLENGTH) = 0 THEN
                                Give_Error "Cannot pass array of variable-length strings": EXIT FUNCTION
                            END IF
                        END IF
                        getid idnumber
                        IF Error_Happened THEN EXIT FUNCTION
                        n$ = "UDT_" + RTRIM$(id.n)
                        IF id.arraytype THEN n$ = "ARRAY_" + n$ + "[0]"
                        bytes$ = _TOSTR$(udtesize(member_element_id) \ 8)
                        dst$ = "(((char*)" + scope$ + n$ + ")+(" + o$ + "))"
                        t = Type2MemTypeValue(sourcetyp)
                        evaluatetotyp$ = "(ptrszint)" + dst$ + "," + bytes$ + "," + _TOSTR$(t) + "," + _TOSTR$(udt_array_member_bytes(member_element_id)) + ",sf_mem_lock"
                        EXIT FUNCTION
                    END IF
                END IF
            END IF

            'whole array reference examplename()?
            IF RIGHT$(e$, 2) = sp3 + "0" THEN
                'use -7 type method
                IF sourcetyp AND ISSTRING THEN
                    IF (sourcetyp AND ISFIXEDLENGTH) = 0 THEN
                        Give_Error "Cannot pass array of variable-length strings": EXIT FUNCTION
                    END IF
                END IF
                GOTO method2useall__7
            END IF

            idnumber = VAL(e$)
            getid idnumber
            IF Error_Happened THEN EXIT FUNCTION
            IF (id.arraytype AND ISUDT) <> 0 THEN
                u = id.arraytype AND UDTMASK
                IF id.dynudt AND UDTDynHasMemberArrays%(u, id.dynudtmode) THEN Give_Error "_MEM cannot reference a TYPE value that contains explicit _Dynamic member arrays": EXIT FUNCTION
                IF id.dynudt AND udtxvariable(u) THEN Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION
            END IF
            n$ = RTRIM$(id.callname)
            lk$ = "(mem_lock*)((ptrszint*)" + n$ + ")[" + _TOSTR$(4 * id.arrayelements + 4 + 1 - 1) + "]"

            'assume a specific element

            IF sourcetyp AND ISSTRING THEN
                IF sourcetyp AND ISFIXEDLENGTH THEN
                    bytes$ = _TOSTR$(id.tsize)
                    e$ = refer(e$, sourcetyp, 0)
                    IF Error_Happened THEN EXIT FUNCTION
                    'evaluatetotyp$ = "byte_element((uint64)" + e$ + "->chr," + bytes$ + "," + NewByteElement$ + ")"
                    'IF targettyp = -5 THEN evaluatetotyp$ = bytes$
                    'IF targettyp = -6 THEN evaluatetotyp$ = e$ + "->chr"

                    t = Type2MemTypeValue(sourcetyp)
                    evaluatetotyp$ = "(ptrszint)" + e$ + "->chr," + bytes$ + "," + _TOSTR$(t) + "," + bytes$ + "," + lk$

                ELSE

                    Give_Error "_MEMELEMENT cannot reference variable-length strings": EXIT FUNCTION

                END IF
                EXIT FUNCTION
            END IF

            e$ = refer(e$, sourcetyp, 0)
            IF Error_Happened THEN EXIT FUNCTION
            e$ = "(&(" + e$ + "))"
            bytes$ = _TOSTR$((sourcetyp AND UDTMASK) \ 8)
            'evaluatetotyp$ = "byte_element((uint64)" + e$ + "," + bytes$ + "," + NewByteElement$ + ")"
            'IF targettyp = -5 THEN evaluatetotyp$ = bytes$
            'IF targettyp = -6 THEN evaluatetotyp$ = e$

            t = Type2MemTypeValue(sourcetyp)
            evaluatetotyp$ = "(ptrszint)" + e$ + "," + bytes$ + "," + _TOSTR$(t) + "," + bytes$ + "," + lk$

            EXIT FUNCTION
        END IF 'isarray

        IF dynmemlockexpr <> "" THEN
            IF (sourcetyp AND ISARRAY) = 0 AND (sourcetyp AND ISUDT) = 0 AND (sourcetyp AND ISSTRING) = 0 THEN
                e$ = refer(e$, sourcetyp, 1)
                IF Error_Happened THEN EXIT FUNCTION
                size = (sourcetyp AND UDTMASK) \ 8
                t = Type2MemTypeValue(sourcetyp)
                evaluatetotyp$ = "(ptrszint)" + e$ + "," + _TOSTR$(size) + "," + _TOSTR$(t) + "," + _TOSTR$(size) + "," + dynmemlockexpr
                EXIT FUNCTION
            END IF
        END IF

        IF sourcetyp AND ISSTRING THEN 'String -> byte_element(offset,bytes)
            IF sourcetyp AND ISFIXEDLENGTH THEN
                idnumber = VAL(e$)
                getid idnumber
                IF Error_Happened THEN EXIT FUNCTION
                bytes$ = _TOSTR$(id.tsize)
                e$ = refer(e$, sourcetyp, 0)
                IF Error_Happened THEN EXIT FUNCTION
            ELSE
                Give_Error "_MEMELEMENT cannot reference variable-length strings": EXIT FUNCTION
            END IF

            'evaluatetotyp$ = "byte_element((uint64)" + e$ + "->chr," + bytes$ + "," + NewByteElement$ + ")"
            'IF targettyp = -5 THEN evaluatetotyp$ = bytes$
            'IF targettyp = -6 THEN evaluatetotyp$ = e$ + "->chr"

            t = Type2MemTypeValue(sourcetyp)
            evaluatetotyp$ = "(ptrszint)" + e$ + "->chr," + bytes$ + "," + _TOSTR$(t) + "," + bytes$ + ",sf_mem_lock"

            EXIT FUNCTION
        END IF

        'Standard variable -> byte_element(offset,bytes)
        e$ = refer(e$, sourcetyp, 1) 'get the variable's formal name
        IF Error_Happened THEN EXIT FUNCTION
        size = (sourcetyp AND UDTMASK) \ 8 'calculate its size in bytes
        'evaluatetotyp$ = "byte_element((uint64)" + e$ + "," + _TOSTR$(size) + "," + NewByteElement$ + ")"
        'IF targettyp = -5 THEN evaluatetotyp$ = _TOSTR$(size)
        'IF targettyp = -6 THEN evaluatetotyp$ = e$

        t = Type2MemTypeValue(sourcetyp)
        evaluatetotyp$ = "(ptrszint)" + e$ + "," + _TOSTR$(size) + "," + _TOSTR$(t) + "," + _TOSTR$(size) + ",sf_mem_lock"

        EXIT FUNCTION

    END IF '-8










    IF targettyp = -7 THEN '? -> _MEM structure helper {offset, fullsize, typeval, elementsize, sf_mem_lock|???}
        method2useall__7:
        IF (sourcetyp AND ISREFERENCE) = 0 THEN Give_Error "Expected variable name/array element": EXIT FUNCTION
        IF (sourcetyp AND ISOFFSETINBITS) THEN Give_Error "Variable/element cannot be _BIT aligned": EXIT FUNCTION

        ' Whole inline TYPE member arrays must be recognized before the generic UDT path.
        ' Their encoded reference has the form id|parentUDT|memberElement|byteOffset.
        ' The generic UDT path would describe the tail of the parent UDT rather than
        ' the inline member array itself.
        s1 = INSTR(e$, sp3)
        IF s1 THEN s2 = INSTR(s1 + LEN(sp3), e$, sp3) ELSE s2 = 0
        IF s2 THEN s3 = INSTR(s2 + LEN(sp3), e$, sp3) ELSE s3 = 0

        IF s3 <> 0 AND final_member_array_indexed THEN
            idnumber = VAL(LEFT$(e$, s1 - 1))
            u = VAL(MID$(e$, s1 + LEN(sp3), s2 - s1 - LEN(sp3)))
            member_element_id = VAL(MID$(e$, s2 + LEN(sp3), s3 - s2 - LEN(sp3)))

            IF member_element_id > 0 THEN
                IF udtearrayelements(member_element_id) THEN
                    getid idnumber
                    IF Error_Happened THEN EXIT FUNCTION
                    n$ = "UDT_" + RTRIM$(id.n)
                    IF id.arraytype THEN n$ = "ARRAY_" + n$ + "[0]"
                    IF id.dynudt AND UDTMemberDynDesc%(member_element_id) THEN
                        IF DynMemVarStr%(member_element_id) THEN Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION
                        IF DynMemUDTVarStr%(member_element_id) THEN Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION
                        o$ = MID$(e$, s3 + LEN(sp3))
                        elem_bytes = udt_dyn_array_elem_bytes(member_element_id)
                        dst$ = "(((char*)" + scope$ + n$ + ")+(" + o$ + "))"
                        elem_typ = udtetype(member_element_id)
                        t = Type2MemTypeValue(elem_typ)
                        IF dynmemlockexpr = "" THEN Give_Error "_MEM cannot access this explicit _Dynamic TYPE member array": EXIT FUNCTION
                        evaluatetotyp$ = "(ptrszint)" + dst$ + "," + _TOSTR$(elem_bytes) + "," + _TOSTR$(t) + "," + _TOSTR$(elem_bytes) + "," + dynmemlockexpr
                        EXIT FUNCTION
                    END IF
                END IF
            END IF
        END IF

        IF ((sourcetyp AND ISARRAY) <> 0) AND (s3 <> 0) THEN

            IF sourcetyp AND ISSTRING THEN
                IF (sourcetyp AND ISFIXEDLENGTH) = 0 THEN
                    Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION
                END IF
            END IF
            idnumber = VAL(LEFT$(e$, s1 - 1))
            u = VAL(MID$(e$, s1 + LEN(sp3), s2 - s1 - LEN(sp3)))
            member_element_id = VAL(MID$(e$, s2 + LEN(sp3), s3 - s2 - LEN(sp3)))

            ' Whole inline TYPE member array: resolve the inline member block before the
            ' generic parent-UDT path can consume the reference.
            IF member_element_id > 0 THEN
                IF udtearrayelements(member_element_id) THEN
                    o$ = MID$(e$, s3 + LEN(sp3))
                    getid idnumber
                    IF Error_Happened THEN EXIT FUNCTION
                    n$ = "UDT_" + RTRIM$(id.n)
                    IF id.arraytype THEN n$ = "ARRAY_" + n$ + "[0]"
                    IF id.dynudt AND UDTMemberDynDesc%(member_element_id) AND final_member_array_indexed THEN
                        IF DynMemVarStr%(member_element_id) THEN Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION
                        IF DynMemUDTVarStr%(member_element_id) THEN Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION
                        ' Indexed element of a descriptor-backed TYPE member array, e.g. _MEM(ff(3).b(10)).
                        ' The encoded offset o$ already points at the selected element. Do not re-evaluate
                        ' ff(3).b() here; that path can fall back into the bare-member parser guard and raise
                        ' "Expected array index". This branch returns a one-element memory view.
                        elem_bytes = udt_dyn_array_elem_bytes(member_element_id)
                        dst$ = "(((char*)" + scope$ + n$ + ")+(" + o$ + "))"
                        elem_typ = udtetype(member_element_id)
                        t = Type2MemTypeValue(elem_typ)
                        IF dynmemlockexpr = "" THEN Give_Error "_MEM cannot access this explicit _Dynamic TYPE member array": EXIT FUNCTION
                        evaluatetotyp$ = "(ptrszint)" + dst$ + "," + _TOSTR$(elem_bytes) + "," + _TOSTR$(t) + "," + _TOSTR$(elem_bytes) + "," + dynmemlockexpr
                        EXIT FUNCTION
                    END IF
                    IF id.dynudt AND UDTMemberDynDesc%(member_element_id) THEN
                        IF DynMemVarStr%(member_element_id) THEN Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION
                        IF DynMemUDTVarStr%(member_element_id) THEN Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION
                        desc_expr = "(*((ptrszint**)(((char*)" + scope$ + n$ + ")+(" + o$ + "))))"
                        desc_expr = UDTDynArrayDescGuard$(desc_expr, udtearraydims(member_element_id))
                        IF Error_Happened THEN EXIT FUNCTION
                        elem_bytes = udt_dyn_array_elem_bytes(member_element_id)
                        bytes$ = UDTDynArrayBytesExpr$(desc_expr, elem_bytes)
                        IF Error_Happened THEN EXIT FUNCTION
                        dst$ = "((char*)" + desc_expr + "[0])"
                        t = Type2MemTypeValue(sourcetyp)
                        lk$ = "(mem_lock*)(" + desc_expr + "[" + desc_expr + "[3]*4+4])"
                        evaluatetotyp$ = "(ptrszint)" + dst$ + "," + bytes$ + "," + _TOSTR$(t) + "," + _TOSTR$(elem_bytes) + "," + lk$
                        EXIT FUNCTION
                    END IF
                    bytes$ = _TOSTR$(udtesize(member_element_id) \ 8)
                    dst$ = "(((char*)" + scope$ + n$ + ")+(" + o$ + "))"
                    t = Type2MemTypeValue(sourcetyp)
                    evaluatetotyp$ = "(ptrszint)" + dst$ + "," + bytes$ + "," + _TOSTR$(t) + "," + _TOSTR$(udt_array_member_bytes(member_element_id)) + ",sf_mem_lock"
                    EXIT FUNCTION
                END IF
            END IF
        END IF

        IF dynmemlockexpr <> "" AND (sourcetyp AND ISUDT) THEN
            idnumber = VAL(e$)
            i = INSTR(e$, sp3): e$ = RIGHT$(e$, LEN(e$) - i)
            u = VAL(e$)
            i = INSTR(e$, sp3): e$ = RIGHT$(e$, LEN(e$) - i)
            udtElem = VAL(e$)
            i = INSTR(e$, sp3): e$ = RIGHT$(e$, LEN(e$) - i)
            o$ = e$
            getid idnumber
            IF Error_Happened THEN EXIT FUNCTION
            IF udtElem = 0 THEN
                IF udtxvariable(u) THEN Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION
            ELSE
                IF DynMemVarStr%(udtElem) THEN Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION
                IF DynMemUDTVarStr%(udtElem) THEN Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION
            END IF
            n$ = "UDT_" + RTRIM$(id.n)
            IF id.arraytype THEN n$ = "ARRAY_" + n$ + "[0]"
            dst$ = "(((char*)" + scope$ + n$ + ")+(" + o$ + "))"
            IF udtElem = 0 THEN
                elem_bytes = udtxsize(u) \ 8
                IF id.dynudt THEN elem_bytes = UDTDynLayoutSize&(u) \ 8
            ELSE
                elem_bytes = udtesize(udtElem) \ 8
            END IF
            t = Type2MemTypeValue(sourcetyp)
            evaluatetotyp$ = "(ptrszint)" + dst$ + "," + _TOSTR$(elem_bytes) + "," + _TOSTR$(t) + "," + _TOSTR$(elem_bytes) + "," + dynmemlockexpr
            EXIT FUNCTION
        END IF

        'User Defined Type
        IF (sourcetyp AND ISUDT) THEN
            '           print "CI: -2 type from a UDT":sleep 1
            idnumber = VAL(e$)
            i = INSTR(e$, sp3): e$ = RIGHT$(e$, LEN(e$) - i)
            u = VAL(e$) 'closest parent
            i = INSTR(e$, sp3): e$ = RIGHT$(e$, LEN(e$) - i)
            udtElem = VAL(e$)
            i = INSTR(e$, sp3): e$ = RIGHT$(e$, LEN(e$) - i)

            o$ = e$
            getid idnumber
            IF Error_Happened THEN EXIT FUNCTION
            IF udtElem = 0 AND id.arraytype <> 0 THEN
                IF udtxvariable(u) THEN
                    IF UDTDynHasMemberArrays%(u, 1) THEN Give_Error "_MEM cannot reference a TYPE value that contains explicit _Dynamic member arrays": EXIT FUNCTION
                END IF
            END IF

            n$ = "UDT_" + RTRIM$(id.n)
            IF id.arraytype THEN
                n$ = "ARRAY_" + n$ + "[0]"

                ' Whole UDT array reference like Parent() must start at byte offset 0.
                ' The encoded o$ form used here is not reliable for _MEM size/address on the
                ' parent whole-array case, so force the base of the array.
                IF LEFT$(o$, 4) = "(0)*" OR LEFT$(o$, 5) = "((0)*" THEN
                    o$ = "0"
                END IF
            END IF

            method2usealludt__7:
            bytes$ = variablesize$(-1) + "-(" + o$ + ")"
            IF Error_Happened THEN EXIT FUNCTION
            dst$ = "(((char*)" + scope$ + n$ + ")+(" + o$ + "))"


            'evaluatetotyp$ = "byte_element((uint64)" + dst$ + "," + bytes$ + "," + NewByteElement$ + ")"

            'note: myudt.myelement results in a size of 1 because it is a continuous run of no consistent granularity
            IF udtElem <> 0 THEN size = 1 ELSE size = udtxsize(u) \ 8
            IF udtElem = 0 AND id.dynudt THEN size = UDTDynLayoutSize&(u) \ 8

            t = Type2MemTypeValue(sourcetyp)
            evaluatetotyp$ = "(ptrszint)" + dst$ + "," + bytes$ + "," + _TOSTR$(t) + "," + _TOSTR$(size) + ",sf_mem_lock"

            EXIT FUNCTION
        END IF

        'Array reference
        IF (sourcetyp AND ISARRAY) THEN
            ' Inline member arrays (unmarked or _Static) have no runtime array descriptor and
            ' no array-specific lock. The returned mem block therefore uses the start address of the inline
            ' region, its total byte size and the byte size of a single nested element.
            s1 = INSTR(e$, sp3)
            IF s1 THEN s2 = INSTR(s1 + LEN(sp3), e$, sp3) ELSE s2 = 0
            IF s2 THEN s3 = INSTR(s2 + LEN(sp3), e$, sp3) ELSE s3 = 0
            IF s3 THEN
                IF sourcetyp AND ISSTRING THEN
                    IF (sourcetyp AND ISFIXEDLENGTH) = 0 THEN
                        Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION
                    END IF
                END IF
                idnumber = VAL(LEFT$(e$, s1 - 1))
                u = VAL(MID$(e$, s1 + LEN(sp3), s2 - s1 - LEN(sp3)))
                member_element_id = VAL(MID$(e$, s2 + LEN(sp3), s3 - s2 - LEN(sp3)))
                ' Whole inline TYPE member array: use the inline member block directly because
                ' this storage has no separate array descriptor.
                IF member_element_id > 0 THEN
                    IF udtearrayelements(member_element_id) THEN
                        o$ = MID$(e$, s3 + LEN(sp3))
                        getid idnumber
                        IF Error_Happened THEN EXIT FUNCTION
                        n$ = "UDT_" + RTRIM$(id.n): IF id.arraytype THEN n$ = "ARRAY_" + n$ + "[0]"
                        IF id.dynudt AND UDTMemberDynDesc%(member_element_id) THEN
                            desc_expr = "(*((ptrszint**)(((char*)" + scope$ + n$ + ")+(" + o$ + "))))"
                            desc_expr = UDTDynArrayDescGuard$(desc_expr, udtearraydims(member_element_id))
                            IF Error_Happened THEN EXIT FUNCTION
                            elem_bytes = udt_dyn_array_elem_bytes(member_element_id)
                            bytes$ = UDTDynArrayBytesExpr$(desc_expr, elem_bytes)
                            IF Error_Happened THEN EXIT FUNCTION
                            dst$ = "((char*)" + desc_expr + "[0])"
                            t = Type2MemTypeValue(sourcetyp)
                            lk$ = "(mem_lock*)(" + desc_expr + "[" + desc_expr + "[3]*4+4])"
                            evaluatetotyp$ = "(ptrszint)" + dst$ + "," + bytes$ + "," + _TOSTR$(t) + "," + _TOSTR$(elem_bytes) + "," + lk$
                            EXIT FUNCTION
                        END IF
                        bytes$ = _TOSTR$(udtesize(member_element_id) \ 8)
                        dst$ = "(((char*)" + scope$ + n$ + ")+(" + o$ + "))"
                        t = Type2MemTypeValue(sourcetyp)
                        evaluatetotyp$ = "(ptrszint)" + dst$ + "," + bytes$ + "," + _TOSTR$(t) + "," + _TOSTR$(udt_array_member_bytes(member_element_id)) + ",sf_mem_lock"
                        EXIT FUNCTION
                    END IF
                END IF
            END IF

            IF sourcetyp AND ISSTRING THEN
                IF (sourcetyp AND ISFIXEDLENGTH) = 0 THEN
                    Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION
                END IF
            END IF

            idnumber = VAL(e$)
            getid idnumber
            IF Error_Happened THEN EXIT FUNCTION
            IF (id.arraytype AND ISUDT) <> 0 THEN
                u = id.arraytype AND UDTMASK
                IF id.dynudt AND UDTDynHasMemberArrays%(u, id.dynudtmode) THEN Give_Error "_MEM cannot reference a TYPE value that contains explicit _Dynamic member arrays": EXIT FUNCTION
                IF id.dynudt AND udtxvariable(u) THEN Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION
            END IF

            n$ = RTRIM$(id.callname)
            lk$ = "(mem_lock*)((ptrszint*)" + n$ + ")[" + _TOSTR$(4 * id.arrayelements + 4 + 1 - 1) + "]"

            tsize = id.tsize 'used later to determine element size of fixed length strings
            'note: array references consist of idnumber|unmultiplied-element-index
            index$ = RIGHT$(e$, LEN(e$) - INSTR(e$, sp3)) 'get element index
            bytes$ = variablesize$(-1)
            IF Error_Happened THEN EXIT FUNCTION
            e$ = refer(e$, sourcetyp, 0)
            IF Error_Happened THEN EXIT FUNCTION

            IF sourcetyp AND ISSTRING THEN
                e$ = "((" + e$ + ")->chr)" '[2013] handle fixed string arrays differently because they are already pointers
            ELSE
                e$ = "(&(" + e$ + "))"
            END IF

            '           print "CI: array: e$["+e$+"], bytes$["+bytes$+"]":sleep 1
            'calculate size of elements
            IF sourcetyp AND ISSTRING THEN
                bytes = tsize
            ELSE
                bytes = (sourcetyp AND UDTMASK) \ 8
            END IF
            bytes$ = bytes$ + "-(" + _TOSTR$(bytes) + "*(" + index$ + "))"

            t = Type2MemTypeValue(sourcetyp)
            evaluatetotyp$ = "(ptrszint)" + e$ + "," + bytes$ + "," + _TOSTR$(t) + "," + _TOSTR$(bytes) + "," + lk$

            EXIT FUNCTION
        END IF

        IF dynmemlockexpr <> "" THEN
            IF (sourcetyp AND ISARRAY) = 0 AND (sourcetyp AND ISUDT) = 0 AND (sourcetyp AND ISSTRING) = 0 THEN
                e$ = refer(e$, sourcetyp, 1)
                IF Error_Happened THEN EXIT FUNCTION
                size = (sourcetyp AND UDTMASK) \ 8
                t = Type2MemTypeValue(sourcetyp)
                evaluatetotyp$ = "(ptrszint)" + e$ + "," + _TOSTR$(size) + "," + _TOSTR$(t) + "," + _TOSTR$(size) + "," + dynmemlockexpr
                EXIT FUNCTION
            END IF
        END IF

        'String
        IF sourcetyp AND ISSTRING THEN
            IF (sourcetyp AND ISFIXEDLENGTH) = 0 THEN Give_Error "_MEM cannot reference variable-length strings": EXIT FUNCTION

            idnumber = VAL(e$)
            getid idnumber: IF Error_Happened THEN EXIT FUNCTION
            bytes$ = _TOSTR$(id.tsize)
            e$ = refer(e$, sourcetyp, 0): IF Error_Happened THEN EXIT FUNCTION

            t = Type2MemTypeValue(sourcetyp)
            evaluatetotyp$ = "(ptrszint)" + e$ + "->chr," + bytes$ + "," + _TOSTR$(t) + "," + bytes$ + ",sf_mem_lock"

            EXIT FUNCTION
        END IF

        'Standard variable -> byte_element(offset,bytes)
        e$ = refer(e$, sourcetyp, 1) 'get the variable's formal name
        IF Error_Happened THEN EXIT FUNCTION
        size = (sourcetyp AND UDTMASK) \ 8 'calculate its size in bytes

        t = Type2MemTypeValue(sourcetyp)
        evaluatetotyp$ = "(ptrszint)" + e$ + "," + _TOSTR$(size) + "," + _TOSTR$(t) + "," + _TOSTR$(size) + ",sf_mem_lock"

        EXIT FUNCTION

    END IF '-7 _MEM structure helper


    IF targettyp = -2 THEN '? -> byte_element(offset,max possible bytes)
        method2useall:
        ' print "CI: eval2typ detected target type of -2 for ["+a2$+"] evaluated as ["+e$+"]":sleep 1

        IF (sourcetyp AND ISREFERENCE) = 0 THEN Give_Error "Expected variable name/array element": EXIT FUNCTION
        IF (sourcetyp AND ISOFFSETINBITS) THEN Give_Error "Variable/element cannot be _BIT aligned": EXIT FUNCTION

        ' Whole inline TYPE member arrays (unmarked or _Static) carry ISARRAY plus element type flags (often ISUDT).
        ' Recognize the special id|parentUDT|memberElement|byteOffset reference before the generic UDT
        ' branch so whole-array helper requests do not collapse to a single element size.
        IF (sourcetyp AND ISARRAY) THEN
            s1 = INSTR(e$, sp3)
            IF s1 THEN s2 = INSTR(s1 + LEN(sp3), e$, sp3) ELSE s2 = 0
            IF s2 THEN s3 = INSTR(s2 + LEN(sp3), e$, sp3) ELSE s3 = 0
            IF s3 THEN
                idnumber = VAL(LEFT$(e$, s1 - 1))
                u = VAL(MID$(e$, s1 + LEN(sp3), s2 - s1 - LEN(sp3)))
                member_element_id = VAL(MID$(e$, s2 + LEN(sp3), s3 - s2 - LEN(sp3)))
                IF member_element_id > 0 THEN
                    IF udtearrayelements(member_element_id) THEN
                        o$ = MID$(e$, s3 + LEN(sp3))
                        getid idnumber
                        IF Error_Happened THEN EXIT FUNCTION
                        n$ = "UDT_" + RTRIM$(id.n): IF id.arraytype THEN n$ = "ARRAY_" + n$ + "[0]"
                        bytes$ = _TOSTR$(udtesize(member_element_id) \ 8)
                        dst$ = "(((char*)" + scope$ + n$ + ")+(" + o$ + "))"
                        evaluatetotyp$ = "byte_element((uint64)" + dst$ + "," + bytes$ + "," + NewByteElement$ + ")"
                        IF targettyp = -5 THEN evaluatetotyp$ = bytes$
                        IF targettyp = -6 THEN evaluatetotyp$ = dst$
                        EXIT FUNCTION
                    END IF
                END IF
            END IF
        END IF

        'User Defined Type -> byte_element(offset,bytes)
        IF (sourcetyp AND ISUDT) THEN
            '           print "CI: -2 type from a UDT":sleep 1
            idnumber = VAL(e$)
            i = INSTR(e$, sp3): e$ = RIGHT$(e$, LEN(e$) - i)
            u = VAL(e$) 'closest parent
            i = INSTR(e$, sp3): e$ = RIGHT$(e$, LEN(e$) - i)
            udtElem = VAL(e$)
            i = INSTR(e$, sp3): e$ = RIGHT$(e$, LEN(e$) - i)
            o$ = e$
            getid idnumber
            IF Error_Happened THEN EXIT FUNCTION
            n$ = "UDT_" + RTRIM$(id.n): IF id.arraytype THEN n$ = "ARRAY_" + n$ + "[0]"
            method2usealludt:
            bytes$ = variablesize$(-1) + "-(" + o$ + ")"
            IF Error_Happened THEN EXIT FUNCTION
            dst$ = "(((char*)" + scope$ + n$ + ")+(" + o$ + "))"
            evaluatetotyp$ = "byte_element((uint64)" + dst$ + "," + bytes$ + "," + NewByteElement$ + ")"
            IF targettyp = -5 THEN evaluatetotyp$ = bytes$
            IF targettyp = -6 THEN evaluatetotyp$ = dst$
            EXIT FUNCTION
        END IF

        'Array reference -> byte_element(offset,bytes)
        IF (sourcetyp AND ISARRAY) THEN
            ' Whole inline TYPE member arrays also flow through the array target types, but their encoded
            ' reference carries parent-UDT metadata instead of a classic array index. Use the recorded byte
            ' offset and member size to build a byte_element view of the inline block.
            s1 = INSTR(e$, sp3)
            IF s1 THEN s2 = INSTR(s1 + LEN(sp3), e$, sp3) ELSE s2 = 0
            IF s2 THEN s3 = INSTR(s2 + LEN(sp3), e$, sp3) ELSE s3 = 0
            IF s3 THEN
                idnumber = VAL(LEFT$(e$, s1 - 1))
                u = VAL(MID$(e$, s1 + LEN(sp3), s2 - s1 - LEN(sp3)))
                member_element_id = VAL(MID$(e$, s2 + LEN(sp3), s3 - s2 - LEN(sp3)))

                ' Whole inline TYPE member array: build the byte_element view from the inline
                ' member block instead of treating it like a normal indexed array reference.
                IF member_element_id > 0 THEN
                    IF udtearrayelements(member_element_id) THEN
                        o$ = MID$(e$, s3 + LEN(sp3))
                        getid idnumber
                        IF Error_Happened THEN EXIT FUNCTION
                        n$ = "UDT_" + RTRIM$(id.n): IF id.arraytype THEN n$ = "ARRAY_" + n$ + "[0]"
                        bytes$ = _TOSTR$(udtesize(member_element_id) \ 8)
                        dst$ = "(((char*)" + scope$ + n$ + ")+(" + o$ + "))"
                        evaluatetotyp$ = "byte_element((uint64)" + dst$ + "," + bytes$ + "," + NewByteElement$ + ")"
                        IF targettyp = -5 THEN evaluatetotyp$ = bytes$
                        IF targettyp = -6 THEN evaluatetotyp$ = dst$
                        EXIT FUNCTION
                    END IF
                END IF
            END IF

            'array of variable length strings (special case, can only refer to single element)
            IF sourcetyp AND ISSTRING THEN
                IF (sourcetyp AND ISFIXEDLENGTH) = 0 THEN
                    e$ = refer(e$, sourcetyp, 0)
                    IF Error_Happened THEN EXIT FUNCTION
                    evaluatetotyp$ = "byte_element((uint64)" + e$ + "->chr," + e$ + "->len," + NewByteElement$ + ")"
                    IF targettyp = -5 THEN evaluatetotyp$ = e$ + "->len"
                    IF targettyp = -6 THEN evaluatetotyp$ = e$ + "->chr"
                    EXIT FUNCTION
                END IF
            END IF
            idnumber = VAL(e$)
            getid idnumber
            IF Error_Happened THEN EXIT FUNCTION
            tsize = id.tsize 'used later to determine element size of fixed length strings
            'note: array references consist of idnumber|unmultiplied-element-index
            index$ = RIGHT$(e$, LEN(e$) - INSTR(e$, sp3)) 'get element index
            bytes$ = variablesize$(-1)
            IF Error_Happened THEN EXIT FUNCTION
            IF ((sourcetyp AND ISSTRING) <> 0) AND ((sourcetyp AND ISFIXEDLENGTH) <> 0) THEN
                ' Fixed-length string arrays are stored as one flat byte buffer. Do not
                ' use refer() here: refer() returns a temporary qbs* wrapper for one
                ' element, and taking &(qbs_new_fixed(...)) is invalid C++ and points
                ' at the temporary wrapper expression, not at the array payload.
                n$ = RTRIM$(id.callname)
                e$ = "(&((uint8*)(" + n$ + "[0]))[(" + index$ + ")*" + _TOSTR$(tsize) + "])"
            ELSE
                e$ = refer(e$, sourcetyp, 0)
                IF Error_Happened THEN EXIT FUNCTION
                e$ = "(&(" + e$ + "))"
            END IF
            '           print "CI: array: e$["+e$+"], bytes$["+bytes$+"]":sleep 1
            'calculate size of elements
            IF sourcetyp AND ISSTRING THEN
                bytes = tsize
            ELSE
                bytes = (sourcetyp AND UDTMASK) \ 8
            END IF
            bytes$ = "(" + bytes$ + "-(" + _TOSTR$(bytes) + "*(" + index$ + ")))"
            evaluatetotyp$ = "byte_element((uint64)" + e$ + "," + bytes$ + "," + NewByteElement$ + ")"
            IF targettyp = -5 THEN evaluatetotyp$ = bytes$
            IF targettyp = -6 THEN evaluatetotyp$ = e$
            '           print "CI: array ->["+"byte_element((uint64)" + e$ + "," + bytes$+ ","+NewByteElement$+")"+"]":sleep 1
            EXIT FUNCTION
        END IF

        'String -> byte_element(offset,bytes)
        IF sourcetyp AND ISSTRING THEN
            IF sourcetyp AND ISFIXEDLENGTH THEN
                idnumber = VAL(e$)
                getid idnumber
                IF Error_Happened THEN EXIT FUNCTION
                bytes$ = _TOSTR$(id.tsize)
                e$ = refer(e$, sourcetyp, 0)
                IF Error_Happened THEN EXIT FUNCTION
            ELSE
                e$ = refer(e$, sourcetyp, 0)
                IF Error_Happened THEN EXIT FUNCTION
                bytes$ = e$ + "->len"
            END IF
            evaluatetotyp$ = "byte_element((uint64)" + e$ + "->chr," + bytes$ + "," + NewByteElement$ + ")"
            IF targettyp = -5 THEN evaluatetotyp$ = bytes$
            IF targettyp = -6 THEN evaluatetotyp$ = e$ + "->chr"
            EXIT FUNCTION
        END IF

        'Standard variable -> byte_element(offset,bytes)
        e$ = refer(e$, sourcetyp, 1) 'get the variable's formal name
        IF Error_Happened THEN EXIT FUNCTION
        size = (sourcetyp AND UDTMASK) \ 8 'calculate its size in bytes
        evaluatetotyp$ = "byte_element((uint64)" + e$ + "," + _TOSTR$(size) + "," + NewByteElement$ + ")"
        IF targettyp = -5 THEN evaluatetotyp$ = _TOSTR$(size)
        IF targettyp = -6 THEN evaluatetotyp$ = e$
        EXIT FUNCTION

    END IF '-2 byte_element(offset,bytes)



    'string?
    IF (sourcetyp AND ISSTRING) <> (targettyp AND ISSTRING) THEN
        Give_Error "Illegal string-number conversion": EXIT FUNCTION
    END IF

    IF (sourcetyp AND ISSTRING) THEN
        evaluatetotyp$ = e$
        IF (sourcetyp AND ISREFERENCE) THEN
            evaluatetotyp$ = refer(e$, sourcetyp, 0)
            IF Error_Happened THEN EXIT FUNCTION
        END IF
        EXIT FUNCTION
    END IF

    'pointer required?
    IF (targettyp AND ISPOINTER) THEN
        Give_Error "evaluatetotyp received a request for a pointer (unsupported)": EXIT FUNCTION
        '...
        Give_Error "Invalid pointer": EXIT FUNCTION
    END IF

    'change to "non-pointer" value
    IF (sourcetyp AND ISREFERENCE) THEN
        e$ = refer(e$, sourcetyp, 0)
        IF Error_Happened THEN EXIT FUNCTION
    END IF
    'check if successful
    IF (sourcetyp AND ISPOINTER) THEN
        Give_Error "evaluatetotyp couldn't convert pointer type!": EXIT FUNCTION
    END IF

    'round to integer if required
    IF (sourcetyp AND ISFLOAT) THEN
        IF (targettyp AND ISFLOAT) = 0 THEN
            bits = targettyp AND UDTMASK
            '**32 rounding fix
            IF bits <= 16 THEN e$ = "qbr_float_to_long(" + e$ + ")"
            IF bits > 16 AND bits < 32 THEN e$ = "qbr_double_to_long(" + e$ + ")"
            IF bits >= 32 THEN e$ = "qbr(" + e$ + ")"
        END IF
    END IF

    evaluatetotyp$ = e$
END FUNCTION

FUNCTION findid& (n2$)
    n$ = UCASE$(n2$) 'case insensitive

    'return all strings as 'not found'
    IF ASC(n$) = 34 THEN GOTO noid

    'if findidsecondarg was set, it will be used for finding the name of a sub (not a func or variable)
    secondarg$ = findidsecondarg: findidsecondarg = ""

    'if findanotherid was set, findid will continue scan from last index, otherwise, it will begin a new search
    findanother = findanotherid: findanotherid = 0
    IF findanother <> 0 AND findidinternal <> 2 THEN Give_Error "FINDID() ERROR: Invalid repeat search requested!": EXIT FUNCTION 'cannot continue search, no more indexes left!
    IF Error_Happened THEN EXIT FUNCTION
    '(the above should never happen)
    findid& = 2 '2=not finished searching all indexes

    'separate symbol from name (if a symbol has been added), this is the only way symbols can be passed to findid
    i = 0
    i = INSTR(n$, "~"): IF i THEN GOTO gotsc
    i = INSTR(n$, "`"): IF i THEN GOTO gotsc
    i = INSTR(n$, "%"): IF i THEN GOTO gotsc
    i = INSTR(n$, "&"): IF i THEN GOTO gotsc
    i = INSTR(n$, "!"): IF i THEN GOTO gotsc
    i = INSTR(n$, "#"): IF i THEN GOTO gotsc
    i = INSTR(n$, "$"): IF i THEN GOTO gotsc
    gotsc:
    IF i THEN
        sc$ = RIGHT$(n$, LEN(n$) - i + 1): n$ = LEFT$(n$, i - 1)
        IF sc$ = "`" OR sc$ = "~`" THEN sc$ = sc$ + "1" 'clarify abbreviated 1 bit reference
    ELSE
        '''    'no symbol passed, so check what symbol could be assumed under the current DEF...
        '''    v = ASC(n$): IF v = 95 THEN v = 27 ELSE v = v - 64
        '''    IF v >= 1 AND v <= 27 THEN 'safeguard against n$ not being a standard name
        '''        couldhavesc$ = defineextaz(v)
        '''        IF couldhavesc$ = "`" OR couldhavesc$ = "~`" THEN couldhavesc$ = couldhavesc$ + "1" 'clarify abbreviated 1 bit reference
        '''    END IF 'safeguard
    END IF

    'optimizations for later comparisons
    insf$ = subfunc + SPACE$(256 - LEN(subfunc))
    secondarg$ = secondarg$ + SPACE$(256 - LEN(secondarg$))
    IF LEN(sc$) THEN scpassed = 1: sc$ = sc$ + SPACE$(8 - LEN(sc$)) ELSE scpassed = 0
    '''IF LEN(couldhavesc$) THEN couldhavesc$ = couldhavesc$ + SPACE$(8 - LEN(couldhavesc$)): couldhavescpassed = 1 ELSE couldhavescpassed = 0
    IF LEN(n$) < 256 THEN n$ = n$ + SPACE$(256 - LEN(n$))

    'FUNCTION HashFind (a$, searchflags, resultflags, resultreference)
    '(0,1,2)z=hashfind[rev]("RUMI",Hashflag_label,resflag,resref)
    '0=doesn't exist
    '1=found, no more items to scan
    '2=found, more items still to scan

    'NEW HASH SYSTEM
    n$ = RTRIM$(n$)
    IF findanother THEN
        hashretry:
        z = HashFindCont(unrequired, i)
    ELSE
        z = HashFind(n$, 1, unrequired, i)
    END IF
    findidinternal = z
    IF z = 0 THEN GOTO noid
    findid = z


    'continue from previous position?
    ''IF findanother THEN start = findidinternal ELSE start = idn

    ''FOR i = start TO 1 STEP -1

    ''    findidinternal = i - 1
    ''    IF findidinternal = 0 THEN findid& = 1 '1=found id, but no more to search

    ''    IF ids(i).n = n$ THEN 'same name?

    'in scope?
    IF ids(i).subfunc = 0 AND ids(i).share = 0 THEN 'scope check required (not a shared variable or the name of a sub/function)
        IF ids(i).insubfunc <> insf$ THEN GOTO findidnomatch
    END IF

    'some subs require a second argument (eg. PUT #, DEF SEG, etc.)
    IF ids(i).subfunc = 2 THEN
        IF ASC(ids(i).secondargmustbe) <> 32 THEN 'exists?
            IF RTRIM$(secondarg$) = UCASE$(RTRIM$(ids(i).secondargmustbe)) THEN
            ELSE
                GOTO findidnomatch
            END IF
        END IF
        IF ASC(ids(i).secondargcantbe) <> 32 THEN 'exists?
            IF RTRIM$(secondarg$) <> UCASE$(RTRIM$(ids(i).secondargcantbe)) THEN
            ELSE
                GOTO findidnomatch
            END IF
        END IF
    END IF 'second sub argument possible

    'must have symbol?
    'typically for variables defined automatically or by a symbol and not the full type name
    imusthave = CVI(ids(i).musthave) 'speed up checks of first 2 characters
    amusthave = imusthave AND 255 'speed up checks of first character
    IF amusthave <> 32 THEN
        IF scpassed THEN
            IF sc$ = ids(i).musthave THEN GOTO findidok
        END IF
        '''    IF couldhavescpassed THEN
        '''        IF couldhavesc$ = ids(i).musthave THEN GOTO findidok
        '''    END IF
        'Q: why is the above triple-commented?
        'A: because if something must have a symbol to refer to it, then a could-have is
        '   not sufficient, and it could mask shared variables in global scope

        'note: symbol defined fixed length strings cannot be referred to by $ without an extension
        'note: sc$ and couldhavesc$ are already changed from ` to `1 to match stored musthave
        GOTO findidnomatch
    END IF

    'may have symbol?
    'typically for variables formally dim'd
    'note: couldhavesc$ needn't be considered for mayhave checks
    IF scpassed THEN 'symbol was passed, so it must match the mayhave symbol
        imayhave = CVI(ids(i).mayhave) 'speed up checks of first 2 characters
        amayhave = imayhave AND 255 'speed up checks of first character
        IF amayhave = 32 THEN GOTO findidnomatch 'it cannot have the symbol passed (nb. musthave symbols have already been ok'd)
        'note: variable length strings are not a problem here, as they can only have one possible extension

        IF amayhave = 36 THEN '"$"
            IF imayhave <> 8228 THEN '"$ "
                'it is a fixed length string
                IF CVI(sc$) = 8228 THEN GOTO findidok 'allow myvariable$ to become myvariable$10
                'allow later comparison to verify if extension is correct
            END IF
        END IF
        IF sc$ <> ids(i).mayhave THEN GOTO findidnomatch
    END IF 'scpassed

    'return id
    findidok:

    id = ids(i)

    t = id.t
    temp$ = refer$(_TOSTR$(i), t, 1)
    manageVariableList "", temp$, 0, 1
    currentid = i
    EXIT FUNCTION

    'END IF 'same name
    findidnomatch:
    'NEXT
    IF z = 2 THEN GOTO hashretry

    'totally unclassifiable
    noid:
    findid& = 0
    currentid = -1
END FUNCTION

FUNCTION FindArray (secure$)
    FindArray = -1
    n$ = secure$
    IF Debug THEN PRINT #9, "func findarray:in:" + n$
    IF alphanumeric(ASC(n$)) = 0 THEN FindArray = 0: EXIT FUNCTION

    'establish whether n$ includes an extension
    i = INSTR(n$, "~"): IF i THEN sc$ = RIGHT$(n$, LEN(n$) - i + 1): n$ = LEFT$(n$, i - 1): GOTO gotsc2
    i = INSTR(n$, "`"): IF i THEN sc$ = RIGHT$(n$, LEN(n$) - i + 1): n$ = LEFT$(n$, i - 1): GOTO gotsc2
    i = INSTR(n$, "%"): IF i THEN sc$ = RIGHT$(n$, LEN(n$) - i + 1): n$ = LEFT$(n$, i - 1): GOTO gotsc2
    i = INSTR(n$, "&"): IF i THEN sc$ = RIGHT$(n$, LEN(n$) - i + 1): n$ = LEFT$(n$, i - 1): GOTO gotsc2
    i = INSTR(n$, "!"): IF i THEN sc$ = RIGHT$(n$, LEN(n$) - i + 1): n$ = LEFT$(n$, i - 1): GOTO gotsc2
    i = INSTR(n$, "#"): IF i THEN sc$ = RIGHT$(n$, LEN(n$) - i + 1): n$ = LEFT$(n$, i - 1): GOTO gotsc2
    i = INSTR(n$, "$"): IF i THEN sc$ = RIGHT$(n$, LEN(n$) - i + 1): n$ = LEFT$(n$, i - 1): GOTO gotsc2
    gotsc2:
    n2$ = n$ + sc$

    IF sc$ <> "" THEN
        'has an extension
        'note! findid must unambiguify ` to `5 or $ to $10 where applicable
        try = findid(n2$): IF Error_Happened THEN EXIT FUNCTION
        DO WHILE try
            IF id.arraytype THEN
                EXIT FUNCTION
            END IF
            IF try = 2 THEN findanotherid = 1: try = findid(n2$) ELSE try = 0
            IF Error_Happened THEN EXIT FUNCTION
        LOOP

    ELSE
        'no extension

        '1. pass as is, without any extension (local)
        try = findid(n2$): IF Error_Happened THEN EXIT FUNCTION
        DO WHILE try
            IF id.arraytype THEN
                IF subfuncn = 0 THEN EXIT FUNCTION
                IF id.insubfuncn = subfuncn THEN EXIT FUNCTION
            END IF
            IF try = 2 THEN findanotherid = 1: try = findid(n2$) ELSE try = 0
            IF Error_Happened THEN EXIT FUNCTION
        LOOP

        '2. that failed, so apply the _define'd extension and pass (local)
        a = ASC(UCASE$(n$)): IF a = 95 THEN a = 91
        a = a - 64 'so A=1, Z=27 and _=28
        n2$ = n$ + defineextaz(a)
        try = findid(n2$): IF Error_Happened THEN EXIT FUNCTION
        DO WHILE try
            IF id.arraytype THEN
                IF subfuncn = 0 THEN EXIT FUNCTION
                IF id.insubfuncn = subfuncn THEN EXIT FUNCTION
                EXIT FUNCTION
            END IF
            IF try = 2 THEN findanotherid = 1: try = findid(n2$) ELSE try = 0
            IF Error_Happened THEN EXIT FUNCTION
        LOOP

        '3. pass as is, without any extension (global)
        n2$ = n$
        try = findid(n2$): IF Error_Happened THEN EXIT FUNCTION
        DO WHILE try
            IF id.arraytype THEN
                EXIT FUNCTION
            END IF
            IF try = 2 THEN findanotherid = 1: try = findid(n2$) ELSE try = 0
            IF Error_Happened THEN EXIT FUNCTION
        LOOP

        '4. that failed, so apply the _define'd extension and pass (global)
        a = ASC(UCASE$(n$)): IF a = 95 THEN a = 91
        a = a - 64 'so A=1, Z=27 and _=28
        n2$ = n$ + defineextaz(a)
        try = findid(n2$): IF Error_Happened THEN EXIT FUNCTION
        DO WHILE try
            IF id.arraytype THEN
                EXIT FUNCTION
            END IF
            IF try = 2 THEN findanotherid = 1: try = findid(n2$) ELSE try = 0
            IF Error_Happened THEN EXIT FUNCTION
        LOOP

    END IF
    FindArray = 0
END FUNCTION



'Main entry point for fixoperationorder
FUNCTION fixoperationorder$ (savea$)
    fixoperationorder = fixoperationorder_rec$(savea$, _FALSE)
END FUNCTION

'Recursive entry point for fixoperationorder
FUNCTION fixoperationorder_rec$ (savea$, bare_arrays)
    DIM udtElem AS LONG
    a$ = savea$
    IF Debug THEN PRINT #9, "fixoperationorder:in:" + a$

    fooindwel = fooindwel + 1

    n = numelements(a$) 'n is maintained throughout function

    IF fooindwel = 1 THEN 'actions to take on initial call only

        'Quick check for duplicate binary operations
        uppercasea$ = UCASE$(a$) 'capitalize it once to reduce calls to ucase over and over
        FOR i = 1 TO n - 1
            temp1$ = getelement(uppercasea$, i)
            temp2$ = getelement(uppercasea$, i + 1)
            IF temp1$ = "AND" AND temp2$ = "AND" THEN Give_Error "Error: AND AND": EXIT FUNCTION
            IF temp1$ = "OR" AND temp2$ = "OR" THEN Give_Error "Error: OR OR": EXIT FUNCTION
            IF temp1$ = "XOR" AND temp2$ = "XOR" THEN Give_Error "Error: XOR XOR": EXIT FUNCTION
            IF temp1$ = "IMP" AND temp2$ = "IMP" THEN Give_Error "Error: IMP IMP": EXIT FUNCTION
            IF temp1$ = "EQV" AND temp2$ = "EQV" THEN Give_Error "Error: EQV EQV": EXIT FUNCTION
            IF temp1$ = "_ANDALSO" AND temp2$ = "_ANDALSO" THEN Give_Error "Error: _ANDALSO _ANDALSO": EXIT FUNCTION
            IF temp1$ = "_ORELSE" AND temp2$ = "_ORELSE" THEN Give_Error "Error: _ORELSE _ORELSE": EXIT FUNCTION
        NEXT

        '----------------A. 'Quick' mismatched brackets check----------------
        b = 0
        a2$ = sp + a$ + sp
        b1$ = sp + "(" + sp
        b2$ = sp + ")" + sp
        i = 1
        findmmb:
        i1 = INSTR(i, a2$, b1$)
        i2 = INSTR(i, a2$, b2$)
        i3 = i1
        IF i2 THEN
            IF i1 = 0 THEN
                i3 = i2
            ELSE
                IF i2 < i1 THEN i3 = i2
            END IF
        END IF
        IF i3 THEN
            IF i3 = i1 THEN b = b + 1
            IF i3 = i2 THEN b = b - 1
            i = i3 + 2
            IF b < 0 THEN Give_Error "Missing (": EXIT FUNCTION
            GOTO findmmb
        END IF
        IF b > 0 THEN Give_Error "Missing )": EXIT FUNCTION

        '----------------B. 'Quick' correction of over-use of +,- ----------------
        'note: the results of this change are beneficial to foolayout
        a2$ = sp + a$ + sp

        'rule 1: change ++ to +
        rule1:
        i = INSTR(a2$, sp + "+" + sp + "+" + sp)
        IF i THEN
            a2$ = LEFT$(a2$, i + 2) + RIGHT$(a2$, LEN(a2$) - i - 4)
            a$ = MID$(a2$, 2, LEN(a2$) - 2)
            n = n - 1
            IF Debug THEN PRINT #9, "fixoperationorder:+/-:" + a$
            GOTO rule1
        END IF

        'rule 2: change -+ to -
        rule2:
        i = INSTR(a2$, sp + "-" + sp + "+" + sp)
        IF i THEN
            a2$ = LEFT$(a2$, i + 2) + RIGHT$(a2$, LEN(a2$) - i - 4)
            a$ = MID$(a2$, 2, LEN(a2$) - 2)
            n = n - 1
            IF Debug THEN PRINT #9, "fixoperationorder:+/-:" + a$
            GOTO rule2
        END IF

        'rule 3: change anyoperator-- to anyoperator
        rule3:
        IF INSTR(a2$, sp + "-" + sp + "-" + sp) THEN
            FOR i = 1 TO n - 2
                IF isoperator(getelement(a$, i)) THEN
                    IF getelement(a$, i + 1) = "-" THEN
                        IF getelement(a$, i + 2) = "-" THEN
                            removeelements a$, i + 1, i + 2, 0
                            a2$ = sp + a$ + sp
                            n = n - 2
                            IF Debug THEN PRINT #9, "fixoperationorder:+/-:" + a$
                            GOTO rule3
                        END IF
                    END IF
                END IF
            NEXT
        END IF 'rule 3



        '----------------C. 'Quick' location of negation----------------
        'note: the results of this change are beneficial to foolayout

        'for numbers...
        'before: anyoperator,-,number
        'after:  anyoperator,-number

        'for variables...
        'before: anyoperator,-,variable
        'after:  anyoperator,CHR$(241),variable

        'exception for numbers followed by ^... (they will be bracketed up along with the ^ later)
        'before: anyoperator,-,number,^
        'after:  anyoperator,CHR$(241),number,^

        FOR i = 1 TO n - 1
            IF i > n - 1 THEN EXIT FOR 'n changes, so manually exit if required

            IF ASC(getelement(a$, i)) = 45 THEN '-

                neg = 0
                IF i = 1 THEN
                    neg = 1
                ELSE
                    a2$ = getelement(a$, i - 1)
                    c = ASC(a2$)
                    IF c = 40 OR c = 44 THEN '(,
                        neg = 1
                    ELSE
                        IF isoperator(a2$) THEN neg = 1
                    END IF '()
                END IF 'i=1
                IF neg = 1 THEN

                    a2$ = getelement(a$, i + 1)
                    c = ASC(a2$)
                    IF c >= 48 AND c <= 57 THEN
                        c2 = 0: IF i < n - 1 THEN c2 = ASC(getelement(a$, i + 2))
                        IF c2 <> 94 THEN 'not ^
                            'number...
                            i2 = INSTR(a2$, ",")
                            IF i2 AND ASC(a2$, i2 + 1) <> 38 THEN '&H/&O/&B values don't need the assumed negation
                                a2$ = "-" + LEFT$(a2$, i2) + "-" + RIGHT$(a2$, LEN(a2$) - i2)
                            ELSE
                                a2$ = "-" + a2$
                            END IF
                            removeelements a$, i, i + 1, 0
                            insertelements a$, i - 1, a2$
                            n = n - 1
                            IF Debug THEN PRINT #9, "fixoperationorder:negation:" + a$

                            GOTO negdone

                        END IF
                    END IF


                    'not a number (or for exceptions)...
                    removeelements a$, i, i, 0
                    insertelements a$, i - 1, CHR$(241)
                    IF Debug THEN PRINT #9, "fixoperationorder:negation:" + a$

                END IF 'isoperator
            END IF '-
            negdone:
        NEXT



    END IF 'fooindwel=1



    '----------------D. 'Quick' Add 'power of' with negation {}bracketing to bottom bracket level----------------
    pownegused = 0
    powneg:
    IF INSTR(a$, "^" + sp + CHR$(241)) THEN 'quick check
        b = 0
        b1 = 0
        FOR i = 1 TO n
            a2$ = getelement(a$, i)
            c = ASC(a2$)
            IF c = 40 THEN b = b + 1
            IF c = 41 THEN b = b - 1
            IF b = 0 THEN
                IF b1 THEN
                    IF isoperator(a2$) THEN
                        IF a2$ <> "^" AND a2$ <> CHR$(241) THEN
                            insertelements a$, i - 1, "}"
                            insertelements a$, b1, "{"
                            n = n + 2
                            IF Debug THEN PRINT #9, "fixoperationorder:^-:" + a$
                            GOTO powneg
                            pownegused = 1
                        END IF
                    END IF
                END IF
                IF c = 94 THEN '^
                    IF getelement$(a$, i + 1) = CHR$(241) THEN b1 = i: i = i + 1
                END IF
            END IF 'b=0
        NEXT i
        IF b1 THEN
            insertelements a$, b1, "{"
            a$ = a$ + sp + "}"
            n = n + 2
            IF Debug THEN PRINT #9, "fixoperationorder:^-:" + a$
            pownegused = 1
            GOTO powneg
        END IF

    END IF 'quick check


    '----------------E. Find lowest & highest operator level in bottom bracket level----------------
    NOT_recheck:
    lco = 255
    hco = 0
    b = 0
    FOR i = 1 TO n
        a2$ = getelement(a$, i)
        c = ASC(a2$)
        IF c = 40 OR c = 123 THEN b = b + 1
        IF c = 41 OR c = 125 THEN b = b - 1
        IF b = 0 THEN
            op = isoperator(a2$)
            IF op THEN
                IF op < lco THEN lco = op
                IF op > hco THEN hco = op
            END IF
        END IF
    NEXT

    '----------------F. Add operator {}bracketting----------------
    'apply bracketting only if required
    IF hco <> 0 THEN 'operators were used
        IF lco <> hco THEN
            'brackets needed

            IF lco = 9 THEN 'NOT exception (check the value if isoperator() is changed!)
                'Step 1: Add brackets as follows ~~~ ( NOT ( ~~~ NOT ~~~ NOT ~~~ NOT ~~~ ))
                'Step 2: Recheck line from beginning
                IF n = 1 THEN Give_Error "Expected NOT ...": EXIT FUNCTION
                b = 0
                FOR i = 1 TO n
                    a2$ = getelement(a$, i)
                    c = ASC(a2$)
                    IF c = 40 OR c = 123 THEN b = b + 1
                    IF c = 41 OR c = 125 THEN b = b - 1
                    IF b = 0 THEN
                        IF UCASE$(a2$) = "NOT" THEN
                            IF i = n THEN Give_Error "Expected NOT ...": EXIT FUNCTION
                            IF i = 1 THEN a$ = "NOT" + sp + "{" + sp + getelements$(a$, 2, n) + sp + "}": n = n + 2: GOTO lco_bracketting_done
                            a$ = getelements$(a$, 1, i - 1) + sp + "{" + sp + "NOT" + sp + "{" + sp + getelements$(a$, i + 1, n) + sp + "}" + sp + "}"
                            n = n + 4
                            GOTO NOT_recheck
                        END IF 'not
                    END IF 'b=0
                NEXT
            END IF 'NOT exception

            n2 = n
            b = 0
            a3$ = "{"
            n = 1
            FOR i = 1 TO n2
                a2$ = getelement(a$, i)
                c = ASC(a2$)
                IF c = 40 OR c = 123 THEN b = b + 1
                IF c = 41 OR c = 125 THEN b = b - 1
                IF b = 0 THEN
                    op = isoperator(a2$)
                    IF op = lco THEN
                        IF i = 1 THEN
                            a3$ = a2$ + sp + "{"
                            n = 2
                        ELSE
                            IF i = n2 THEN Give_Error "Expected variable/value after '" + UCASE$(a2$) + "'": EXIT FUNCTION
                            a3$ = a3$ + sp + "}" + sp + a2$ + sp + "{"
                            n = n + 3
                        END IF
                        GOTO fixop0
                    END IF

                END IF 'b=0
                a3$ = a3$ + sp + a2$
                n = n + 1
                fixop0:
            NEXT
            a3$ = a3$ + sp + "}"
            n = n + 1
            a$ = a3$

            lco_bracketting_done:
            IF Debug THEN PRINT #9, "fixoperationorder:lco bracketing["; lco; ","; hco; "]:" + a$

            '--------(F)G. Remove indwelling {}bracketting from power-negation--------
            IF pownegused THEN
                b = 0
                i = 0
                DO
                    i = i + 1
                    IF i > n THEN EXIT DO
                    c = ASC(getelement(a$, i))
                    IF c = 41 OR c = 125 THEN b = b - 1
                    IF (c = 123 OR c = 125) AND b <> 0 THEN
                        removeelements a$, i, i, 0
                        n = n - 1
                        i = i - 1
                        IF Debug THEN PRINT #9, "fixoperationorder:^- {} removed:" + a$
                    END IF
                    IF c = 40 OR c = 123 THEN b = b + 1
                LOOP
            END IF 'pownegused

        END IF 'lco <> hco
    END IF 'hco <> 0

    '--------Bracketting of multiple NOT/negation unary operators--------
    IF LEFT$(a$, 4) = CHR$(241) + sp + CHR$(241) + sp THEN
        a$ = CHR$(241) + sp + "{" + sp + getelements$(a$, 2, n) + sp + "}": n = n + 2
    END IF
    IF UCASE$(LEFT$(a$, 8)) = "NOT" + sp + "NOT" + sp THEN
        a$ = "NOT" + sp + "{" + sp + getelements$(a$, 2, n) + sp + "}": n = n + 2
    END IF

    '----------------H. Identification/conversion of elements within bottom bracket level----------------
    'actions performed:
    '   ->builds f$(tlayout)
    '   ->adds symbols to all numbers
    '   ->evaluates constants to numbers

    f$ = ""
    b = 0
    c = 0
    lastt = 0: lastti = 0
    FOR i = 1 TO n
        f2$ = getelement(a$, i)
        lastc = c
        c = ASC(f2$)

        IF c = 40 OR c = 123 THEN
            IF c <> 40 OR b <> 0 THEN f2$ = "" 'skip temporary & indwelling  brackets
            b = b + 1
            GOTO classdone
        END IF
        IF c = 41 OR c = 125 THEN

            b = b - 1

            'check for "("+sp+")" after literal-string, operator, number or nothing
            IF b = 0 THEN 'must be within the lowest level
                IF c = 41 THEN
                    IF lastc = 40 THEN
                        IF lastti = i - 2 OR lastti = 0 THEN
                            IF lastt >= 0 AND lastt <= 3 THEN
                                Give_Error "Unexpected (": EXIT FUNCTION
                            END IF
                        END IF
                    END IF
                END IF
            END IF

            IF c <> 41 OR b <> 0 THEN f2$ = "" 'skip temporary & indwelling  brackets
            GOTO classdone
        END IF

        IF b = 0 THEN

            'classifications/conversions:
            '1. quoted string ("....)
            '2. number
            '3. operator
            '4. constant
            '5. variable/array/udt/function (note: nothing can share the same name as a function except a label)


            'quoted string?
            IF c = 34 THEN '"
                lastt = 1: lastti = i

                ' FIXME: Use createElementString

                'convert \\ to \
                'convert \??? to CHR$(&O???)
                x2 = 1
                x = INSTR(x2, f2$, "\")
                DO WHILE x
                    c2 = ASC(f2$, x + 1)
                    IF c2 = 92 THEN '\\
                        f2$ = LEFT$(f2$, x) + RIGHT$(f2$, LEN(f2$) - x - 1) 'remove second \
                        x2 = x + 1
                    ELSE
                        'octal triplet value
                        c3 = (ASC(f2$, x + 3) - 48) + (ASC(f2$, x + 2) - 48) * 8 + (ASC(f2$, x + 1) - 48) * 64
                        f2$ = LEFT$(f2$, x - 1) + CHR$(c3) + RIGHT$(f2$, LEN(f2$) - x - 3)
                        x2 = x + 1
                    END IF
                    x = INSTR(x2, f2$, "\")
                LOOP
                'remove ',len' (if it exists)
                x = INSTR(2, f2$, CHR$(34) + ","): IF x THEN f2$ = LEFT$(f2$, x)
                GOTO classdone
            END IF

            'number?
            IF (c >= 48 AND c <= 57) OR c = 45 THEN
                lastt = 2: lastti = i

                x = INSTR(f2$, ",")
                IF x THEN
                    removeelements a$, i, i, 0: insertelements a$, i - 1, LEFT$(f2$, x - 1)
                    f2$ = RIGHT$(f2$, LEN(f2$) - x)
                END IF

                IF x = 0 THEN
                    c2 = ASC(f2$, LEN(f2$))
                    IF c2 < 48 OR c2 > 57 THEN
                        x = 1 'extension given
                    ELSE
                        x = INSTR(f2$, "`")
                    END IF
                END IF

                'add appropriate integer symbol if none present
                IF x = 0 THEN
                    f3$ = f2$
                    s$ = ""
                    IF c = 45 THEN
                        s$ = "&&"
                        IF (f3$ < "-2147483648" AND LEN(f3$) = 11) OR LEN(f3$) < 11 THEN s$ = "&"
                        IF (f3$ <= "-32768" AND LEN(f3$) = 6) OR LEN(f3$) < 6 THEN s$ = "%"
                    ELSE
                        s$ = "~&&"
                        IF (f3$ <= "9223372036854775807" AND LEN(f3$) = 19) OR LEN(f3$) < 19 THEN s$ = "&&"
                        IF (f3$ <= "2147483647" AND LEN(f3$) = 10) OR LEN(f3$) < 10 THEN s$ = "&"
                        IF (f3$ <= "32767" AND LEN(f3$) = 5) OR LEN(f3$) < 5 THEN s$ = "%"
                    END IF
                    f3$ = f3$ + s$
                    removeelements a$, i, i, 0: insertelements a$, i - 1, f3$
                END IF 'x=0

                GOTO classdone
            END IF

            'operator?
            IF isoperator(f2$) THEN
                lastt = 3: lastti = i
                IF LEN(f2$) > 1 THEN
                    IF f2$ <> SCase2$(f2$) THEN
                        f2$ = SCase2$(f2$)
                        removeelements a$, i, i, 0
                        insertelements a$, i - 1, f2$
                    END IF
                END IF
                'append negation
                IF f2$ = CHR$(241) THEN f$ = f$ + sp + "-": GOTO classdone_special
                GOTO classdone
            END IF

            IF alphanumeric(c) THEN
                lastt = 4: lastti = i

                IF i < n THEN nextc = ASC(getelement(a$, i + 1)) ELSE nextc = 0

                ' a constant?
                IF nextc <> 40 THEN '<>"(" (not an array)
                    IF lastc <> 46 THEN '<>"." (not an element of a UDT)

                        e$ = UCASE$(f2$)
                        es$ = removesymbol$(e$)
                        IF Error_Happened THEN EXIT FUNCTION

                        hashfound = 0
                        hashname$ = e$
                        hashchkflags = HASHFLAG_CONSTANT
                        hashres = HashFindRev(hashname$, hashchkflags, hashresflags, hashresref)
                        DO WHILE hashres
                            IF constsubfunc(hashresref) = subfuncn OR constsubfunc(hashresref) = 0 THEN
                                IF constdefined(hashresref) THEN
                                    hashfound = 1
                                    EXIT DO
                                END IF
                            END IF
                            IF hashres <> 1 THEN hashres = HashFindCont(hashresflags, hashresref) ELSE hashres = 0
                        LOOP

                        IF hashfound THEN
                            i2 = hashresref
                            'FOR i2 = constlast TO 0 STEP -1
                            'IF e$ = constname(i2) THEN





                            'is a STATIC variable overriding this constant?
                            staticvariable = 0
                            try = findid(e$ + es$)
                            IF Error_Happened THEN EXIT FUNCTION
                            DO WHILE try
                                IF id.arraytype = 0 THEN staticvariable = 1: EXIT DO 'if it's not an array, it's probably a static variable
                                IF try = 2 THEN findanotherid = 1: try = findid(e$ + es$) ELSE try = 0
                                IF Error_Happened THEN EXIT FUNCTION
                            LOOP
                            'add symbol and try again
                            IF staticvariable = 0 THEN
                                IF LEN(es$) = 0 THEN
                                    a = ASC(UCASE$(e$)): IF a = 95 THEN a = 91
                                    a = a - 64 'so A=1, Z=27 and _=28
                                    es2$ = defineextaz(a)
                                    try = findid(e$ + es2$)
                                    IF Error_Happened THEN EXIT FUNCTION
                                    DO WHILE try
                                        IF id.arraytype = 0 THEN staticvariable = 1: EXIT DO 'if it's not an array, it's probably a static variable
                                        IF try = 2 THEN findanotherid = 1: try = findid(e$ + es2$) ELSE try = 0
                                        IF Error_Happened THEN EXIT FUNCTION
                                    LOOP
                                END IF
                            END IF

                            IF staticvariable = 0 THEN

                                t = consttype(i2)
                                IF t AND ISSTRING THEN
                                    IF LEN(es$) > 0 AND es$ <> "$" THEN Give_Error "Type mismatch": EXIT FUNCTION
                                    e$ = conststring(i2)
                                ELSE 'not a string
                                    IF LEN(es$) THEN et = typname2typ(es$) ELSE et = 0
                                    IF Error_Happened THEN EXIT FUNCTION
                                    IF et AND ISSTRING THEN Give_Error "Type mismatch": EXIT FUNCTION
                                    'convert value to general formats
                                    IF t AND ISFLOAT THEN
                                        v## = constfloat(i2)
                                        v&& = v##
                                        v~&& = v&&
                                    ELSE
                                        IF t AND ISUNSIGNED THEN
                                            v~&& = constuinteger(i2)
                                            v&& = v~&&
                                            v## = v&&
                                        ELSE
                                            v&& = constinteger(i2)
                                            v## = v&&
                                            v~&& = v&&
                                        END IF
                                    END IF
                                    'apply type conversion if necessary
                                    IF et THEN t = et
                                    '(todo: range checking)
                                    'convert value into string for returning
                                    IF t AND ISFLOAT THEN
                                        e$ = _TOSTR$(v##)
                                    ELSE
                                        IF t AND ISUNSIGNED THEN
                                            e$ = _TOSTR$(v~&&)
                                        ELSE
                                            e$ = _TOSTR$(v&&)
                                        END IF
                                    END IF

                                    'floats returned by str$ must be converted to qb64 standard format
                                    IF t AND ISFLOAT THEN
                                        t2 = t AND UDTMASK
                                        'find E,D or F
                                        s$ = ""
                                        IF INSTR(e$, "E") THEN s$ = "E"
                                        IF INSTR(e$, "D") THEN s$ = "D"
                                        IF INSTR(e$, "F") THEN s$ = "F"
                                        IF LEN(s$) THEN
                                            'E,D,F found
                                            x = INSTR(e$, s$)
                                            'as incorrect type letter may have been returned by STR$, override it
                                            IF t2 = 32 THEN s$ = "E"
                                            IF t2 = 64 THEN s$ = "D"
                                            IF t2 = 256 THEN s$ = "F"
                                            MID$(e$, x, 1) = s$
                                            IF INSTR(e$, ".") = 0 THEN e$ = LEFT$(e$, x - 1) + ".0" + RIGHT$(e$, LEN(e$) - x + 1): x = x + 2
                                            IF LEFT$(e$, 1) = "." THEN e$ = "0" + e$
                                            IF LEFT$(e$, 2) = "-." THEN e$ = "-0" + RIGHT$(e$, LEN(e$) - 1)
                                            IF INSTR(e$, "+") = 0 AND INSTR(e$, "-") = 0 THEN
                                                e$ = LEFT$(e$, x) + "+" + RIGHT$(e$, LEN(e$) - x)
                                            END IF
                                        ELSE
                                            'E,D,F not found
                                            IF INSTR(e$, ".") = 0 THEN e$ = e$ + ".0"
                                            IF LEFT$(e$, 1) = "." THEN e$ = "0" + e$
                                            IF LEFT$(e$, 2) = "-." THEN e$ = "-0" + RIGHT$(e$, LEN(e$) - 1)
                                            IF t2 = 32 THEN e$ = e$ + "E+0"
                                            IF t2 = 64 THEN e$ = e$ + "D+0"
                                            IF t2 = 256 THEN e$ = e$ + "F+0"
                                        END IF
                                    ELSE
                                        s$ = typevalue2symbol$(t)
                                        IF Error_Happened THEN EXIT FUNCTION
                                        e$ = e$ + s$ 'simply append symbol to integer
                                    END IF

                                END IF 'not a string

                                removeelements a$, i, i, 0
                                insertelements a$, i - 1, e$
                                'alter f2$ here to original casing
                                f2$ = constcname(i2) + es$
                                GOTO classdone

                            END IF 'not static
                            'END IF 'same name
                            'NEXT
                        END IF 'hashfound
                    END IF 'not udt element
                END IF 'not array

                'variable/array/udt?
                u$ = f2$

                try_string$ = f2$
                try_string2$ = try_string$ 'pure version of try_string$

                FOR try_method = 1 TO 4
                    try_string$ = try_string2$
                    IF try_method = 2 OR try_method = 4 THEN
                        dtyp$ = removesymbol(try_string$)
                        IF LEN(dtyp$) = 0 THEN
                            IF isoperator(try_string$) = 0 THEN
                                IF isvalidvariable(try_string$) THEN
                                    IF LEFT$(try_string$, 1) = "_" THEN v = 27 ELSE v = ASC(UCASE$(try_string$)) - 64
                                    try_string$ = try_string$ + defineextaz(v)
                                END IF
                            END IF
                        ELSE
                            try_string$ = try_string2$
                        END IF
                    END IF
                    try = findid(try_string$)
                    IF Error_Happened THEN EXIT FUNCTION
                    DO WHILE try
                        IF (subfuncn = id.insubfuncn AND try_method <= 2) OR try_method >= 3 THEN

                            IF Debug THEN PRINT #9, "found id matching " + f2$

                            'Determine whether we are looking at a function, array or simple variable. Most of the time
                            'a check for nextc = '(' works, but there are exceptional cases such as UBOUND where an array
                            'can appear without its () suffix. Because an array and simple variable can exist with the same
                            'name (and so we may have multiple hash table results), bare_arrays flags that we are evaluating
                            'in this exceptional context. Furthermore, we explicitly ignore simple variables to ensure the
                            'array version is used.
                            IF nextc = 40 THEN '(

                                IF id.arraytype <> 0 OR id.subfunc = 1 THEN 'array or function with parameters
                                    'note: even if it's an array of UDTs, the bracketted index will follow immediately

                                    'correct name
                                    f3$ = f2$
                                    s$ = removesymbol$(f3$)
                                    IF Error_Happened THEN EXIT FUNCTION
                                    IF id.internal_subfunc THEN
                                        f2$ = SCase$(RTRIM$(id.cn)) + s$
                                    ELSE
                                        f2$ = RTRIM$(id.cn) + s$
                                    END IF
                                    removeelements a$, i, i, 0
                                    insertelements a$, i - 1, UCASE$(f2$)
                                    f$ = f$ + f2$ + sp + "(" + sp

                                    'skip (but record with nothing inside them) brackets
                                    b2 = 1 'already in first bracket
                                    FOR i2 = i + 2 TO n
                                        c2 = ASC(getelement(a$, i2))
                                        IF c2 = 40 THEN b2 = b2 + 1
                                        IF c2 = 41 THEN b2 = b2 - 1
                                        IF b2 = 0 THEN EXIT FOR 'note: mismatched brackets check ensures this always succeeds
                                        f$ = f$ + sp
                                    NEXT

                                    'adjust i accordingly
                                    i = i2

                                    f$ = f$ + ")"

                                    'jump to UDT section if array is of UDT type (and elements are referenced)
                                    IF id.arraytype AND ISUDT THEN
                                        IF i < n THEN nextc = ASC(getelement(a$, i + 1)) ELSE nextc = 0
                                        IF nextc = 46 THEN t = id.arraytype: GOTO fooudt
                                    END IF

                                    f$ = f$ + sp
                                    GOTO classdone_special
                                END IF 'id.arraytype
                            END IF 'nextc "("

                            IF nextc <> 40 THEN 'not "(" : simple variable, zero-argument function or bare array
                                IF (NOT bare_arrays AND id.t <> 0) OR id.subfunc = 1 OR (bare_arrays AND id.arraytype <> 0) THEN 'simple variable or zero-argument function or bare array

                                    IF id.t AND ISUDT THEN
                                        'note: it may or may not be followed by a period (eg. if whole udt is being referred to)
                                        'check if next item is a period

                                        'correct name
                                        IF id.internal_subfunc THEN
                                            f2$ = SCase$(RTRIM$(id.cn)) + removesymbol$(f2$)
                                        ELSE
                                            f2$ = RTRIM$(id.cn) + removesymbol$(f2$)
                                        END IF
                                        IF Error_Happened THEN EXIT FUNCTION
                                        removeelements a$, i, i, 0
                                        insertelements a$, i - 1, UCASE$(f2$)
                                        f$ = f$ + f2$



                                        IF nextc <> 46 THEN f$ = f$ + sp: GOTO classdone_special 'no sub-elements referenced
                                        t = id.t

                                        fooudt:

                                        f$ = f$ + sp + "." + sp
                                        udtElem = udtxnext(t AND UDTMASK) 'next element to check
                                        i = i + 2

                                        'loop

                                        '"." encountered, i must be an element
                                        IF i > n THEN Give_Error "Expected .element": EXIT FUNCTION
                                        f2$ = getelement(a$, i)
                                        s$ = removesymbol$(f2$)
                                        IF Error_Happened THEN EXIT FUNCTION
                                        u$ = UCASE$(f2$) + SPACE$(256 - LEN(f2$)) 'fast scanning

                                        'is f$ the same as element e?
                                        fooudtnexte:
                                        IF udtename(udtElem) = u$ THEN
                                            'match found
                                            'todo: check symbol(s$) matches element's type

                                            'correct name
                                            f2$ = RTRIM$(udtecname(udtElem)) + s$
                                            removeelements a$, i, i, 0
                                            insertelements a$, i - 1, UCASE$(f2$)
                                            f$ = f$ + f2$

                                            'If this UDT element is an inline member array, skip its index list here.
                                            'The index expression is recursively formatted later by the normal bracket pass.
                                            'This keeps the UDT context alive for chains such as f.z(1).xx(1), so the
                                            'member after the indexed UDT array element is also corrected to its declared case.
                                            IF udtearrayelements(udtElem) THEN
                                                IF i < n THEN
                                                    IF ASC(getelement(a$, i + 1)) = 40 THEN
                                                        f$ = f$ + sp + "(" + sp
                                                        b2 = 1
                                                        FOR i2 = i + 2 TO n
                                                            c2 = ASC(getelement(a$, i2))
                                                            IF c2 = 40 THEN b2 = b2 + 1
                                                            IF c2 = 41 THEN b2 = b2 - 1
                                                            IF b2 = 0 THEN EXIT FOR
                                                            f$ = f$ + sp
                                                        NEXT
                                                        IF b2 <> 0 THEN Give_Error "Missing )": EXIT FUNCTION
                                                        i = i2
                                                        f$ = f$ + ")"
                                                        IF i = n THEN f$ = f$ + sp: GOTO classdone_special
                                                        nextc = ASC(getelement(a$, i + 1))
                                                        IF nextc = 46 THEN
                                                            t = udtetype(udtElem)
                                                            IF (t AND ISUDT) = 0 THEN Give_Error "Invalid . after element": EXIT FUNCTION
                                                            GOTO fooudt
                                                        END IF
                                                        f$ = f$ + sp: GOTO classdone_special
                                                    END IF
                                                END IF
                                            END IF

                                            IF i = n THEN f$ = f$ + sp: GOTO classdone_special
                                            nextc = ASC(getelement(a$, i + 1))
                                            IF nextc <> 46 THEN f$ = f$ + sp: GOTO classdone_special 'no sub-elements referenced
                                            'sub-element exists
                                            t = udtetype(udtElem)
                                            IF (t AND ISUDT) = 0 THEN Give_Error "Invalid . after element": EXIT FUNCTION
                                            GOTO fooudt

                                        END IF 'match found

                                        'no, so check next element
                                        udtElem = udtenext(udtElem)
                                        IF udtElem = 0 THEN Give_Error "Element not defined": EXIT FUNCTION
                                        GOTO fooudtnexte

                                    END IF 'udt

                                    'non array/udt based variable
                                    f3$ = f2$
                                    s$ = removesymbol$(f3$)
                                    IF Error_Happened THEN EXIT FUNCTION
                                    IF id.internal_subfunc THEN
                                        f2$ = SCase$(RTRIM$(id.cn)) + s$
                                    ELSE
                                        f2$ = RTRIM$(id.cn) + s$
                                    END IF
                                    'change was is returned to uppercase
                                    removeelements a$, i, i, 0
                                    insertelements a$, i - 1, UCASE$(f2$)
                                    GOTO CouldNotClassify
                                END IF 'id.t

                            END IF 'nextc not "("

                        END IF
                        IF try = 2 THEN findanotherid = 1: try = findid(try_string$) ELSE try = 0
                        IF Error_Happened THEN EXIT FUNCTION
                    LOOP
                NEXT 'try method (1-4)
                CouldNotClassify:

                'alphanumeric, but item name is unknown... is it an internal type? if so, use capitals
                f3$ = UCASE$(f2$)
                internaltype = 0
                IF f3$ = "STRING" THEN internaltype = 1
                IF f3$ = "_UNSIGNED" THEN internaltype = 1
                IF f3$ = "_BIT" THEN internaltype = 1
                IF f3$ = "_BYTE" THEN internaltype = 1
                IF f3$ = "INTEGER" THEN internaltype = 1
                IF f3$ = "LONG" THEN internaltype = 1
                IF f3$ = "_INTEGER64" THEN internaltype = 1
                IF f3$ = "SINGLE" THEN internaltype = 1
                IF f3$ = "DOUBLE" THEN internaltype = 1
                IF f3$ = "_FLOAT" THEN internaltype = 1
                IF f3$ = "_OFFSET" THEN internaltype = 1
                IF internaltype = 1 THEN
                    f2$ = SCase2$(f3$)
                    removeelements a$, i, i, 0
                    insertelements a$, i - 1, f3$
                    GOTO classdone
                END IF

                GOTO classdone
            END IF 'alphanumeric

            classdone:
            f$ = f$ + f2$
        END IF 'b=0
        f$ = f$ + sp
        classdone_special:
    NEXT

    IF LEN(f$) THEN f$ = LEFT$(f$, LEN(f$) - 1) 'remove trailing 'sp'

    IF Debug THEN PRINT #9, "fixoperationorder:identification:" + a$, n
    IF Debug THEN PRINT #9, "fixoperationorder:identification(layout):" + f$, n


    '----------------I. Pass (){}bracketed items (if any) to fixoperationorder & build return----------------
    'note: items separated by commas are done separately

    ff$ = ""
    b = 0
    b2 = 0
    p1 = 0 'where level 1 began
    aa$ = ""
    n = numelements(a$)
    FOR i = 1 TO n

        openbracket = 0

        a2$ = getelement(a$, i)

        c = ASC(a2$)



        IF c = 40 OR c = 123 THEN '({
            b = b + 1

            IF b = 1 THEN




                p1 = i + 1
                aa$ = aa$ + "(" + sp

            END IF

            openbracket = 1

            GOTO foopass

        END IF '({

        IF c = 44 THEN ',
            IF b = 1 THEN
                GOTO foopassit
            END IF
        END IF

        IF c = 41 OR c = 125 THEN ')}
            b = b - 1

            IF b = 0 THEN
                foopassit:
                IF p1 <> i THEN
                    bare_array_context = _FALSE
                    IF p1 > 2 THEN
                        token_before_paren$ = getelement(a$, p1 - 2)
                        bare_array_context = (token_before_paren$ = "UBOUND" OR token_before_paren$ = "LBOUND")
                    END IF
                    foo$ = fixoperationorder_rec(getelements(a$, p1, i - 1), bare_array_context)
                    IF Error_Happened THEN EXIT FUNCTION
                    IF LEN(foo$) THEN
                        aa$ = aa$ + foo$ + sp
                        IF c = 125 THEN ff$ = ff$ + tlayout$ + sp ELSE ff$ = ff$ + tlayout$ + sp2 'spacing between ) } , varies
                    END IF
                END IF
                IF c = 44 THEN aa$ = aa$ + "," + sp: ff$ = ff$ + "," + sp ELSE aa$ = aa$ + ")" + sp
                p1 = i + 1
            END IF

            GOTO foopass
        END IF ')}




        IF b = 0 THEN aa$ = aa$ + a2$ + sp


        foopass:

        f2$ = getelementspecial(f$, i)
        IF Error_Happened THEN EXIT FUNCTION
        IF LEN(f2$) THEN

            'use sp2 to join items connected by a period
            IF c = 46 THEN '"."
                IF i > 1 AND i < n THEN 'stupidity check
                    IF LEN(ff$) THEN MID$(ff$, LEN(ff$), 1) = sp2 'convert last spacer to a sp2
                    ff$ = ff$ + "." + sp2
                    GOTO fooloopnxt
                END IF
            END IF

            'spacing just before (
            IF openbracket THEN

                'convert last spacer?
                IF i <> 1 THEN
                    IF isoperator(getelement$(a$, i - 1)) = 0 THEN
                        MID$(ff$, LEN(ff$), 1) = sp2
                    END IF
                END IF
                ff$ = ff$ + f2$ + sp2
            ELSE 'not openbracket
                ff$ = ff$ + f2$ + sp
            END IF

        END IF 'len(f2$)

        fooloopnxt:

    NEXT

    IF LEN(aa$) THEN aa$ = LEFT$(aa$, LEN(aa$) - 1)
    IF LEN(ff$) THEN ff$ = LEFT$(ff$, LEN(ff$) - 1)

    IF Debug THEN PRINT #9, "fixoperationorder:return:" + aa$
    IF Debug THEN PRINT #9, "fixoperationorder:layout:" + ff$
    tlayout$ = ff$
    fixoperationorder_rec$ = aa$

    fooindwel = fooindwel - 1
END FUNCTION




FUNCTION getelementspecial$ (savea$, elenum)
    a$ = savea$
    IF a$ = "" THEN EXIT FUNCTION 'no elements!

    n = 1
    p = 1
    getelementspecialnext:
    i = INSTR(p, a$, sp)

    'avoid sp inside "..."
    i2 = INSTR(p, a$, CHR$(34))
    IF i2 < i AND i2 <> 0 THEN
        i3 = INSTR(i2 + 1, a$, CHR$(34)): IF i3 = 0 THEN Give_Error "Expected " + CHR$(34): EXIT FUNCTION
        i = INSTR(i3, a$, sp)
    END IF

    IF elenum = n THEN
        IF i THEN
            getelementspecial$ = MID$(a$, p, i - p)
        ELSE
            getelementspecial$ = RIGHT$(a$, LEN(a$) - p + 1)
        END IF
        EXIT FUNCTION
    END IF

    IF i = 0 THEN EXIT FUNCTION 'no more elements!
    n = n + 1
    p = i + 1
    GOTO getelementspecialnext
END FUNCTION


SUB getid (i AS LONG)
    IF i = -1 THEN Give_Error "-1 passed to getid!": EXIT SUB

    id = ids(i)

    currentid = i
END SUB

FUNCTION isoperator (a2$)
    a$ = UCASE$(a2$)
    l = 0
    l = l + 1: IF a$ = "_ORELSE" THEN GOTO opfound
    l = l + 1: IF a$ = "_ANDALSO" THEN GOTO opfound
    l = l + 1: IF a$ = "IMP" THEN GOTO opfound
    l = l + 1: IF a$ = "EQV" THEN GOTO opfound
    l = l + 1: IF a$ = "XOR" THEN GOTO opfound
    l = l + 1: IF a$ = "OR" THEN GOTO opfound
    l = l + 1: IF a$ = "AND" THEN GOTO opfound
    l = l + 1: IF a$ = "_NEGATE" THEN GOTO opfound
    l = l + 1: IF a$ = "NOT" THEN GOTO opfound
    l = l + 1
    IF a$ = "=" THEN GOTO opfound
    IF a$ = ">" THEN GOTO opfound
    IF a$ = "<" THEN GOTO opfound
    IF a$ = "<>" THEN GOTO opfound
    IF a$ = "<=" THEN GOTO opfound
    IF a$ = ">=" THEN GOTO opfound
    l = l + 1
    IF a$ = "+" THEN GOTO opfound
    IF a$ = "-" THEN GOTO opfound '!CAREFUL! could be negation
    l = l + 1: IF a$ = "MOD" THEN GOTO opfound
    l = l + 1: IF a$ = "\" THEN GOTO opfound
    l = l + 1
    IF a$ = "*" THEN GOTO opfound
    IF a$ = "/" THEN GOTO opfound
    'NEGATION LEVEL (MUST BE SET AFTER CALLING ISOPERATOR BY CONTEXT)
    l = l + 1: IF a$ = CHR$(241) THEN GOTO opfound
    l = l + 1: IF a$ = "^" THEN GOTO opfound
    EXIT FUNCTION
    opfound:
    isoperator = l
END FUNCTION

FUNCTION isvalidvariable (a$)
    FOR i = 1 TO LEN(a$)
        c = ASC(a$, i)
        t = 0
        IF c >= 48 AND c <= 57 THEN t = 1 'numeric
        IF c >= 65 AND c <= 90 THEN t = 2 'uppercase
        IF c >= 97 AND c <= 122 THEN t = 2 'lowercase
        IF c = 95 THEN t = 2 '_ underscore
        IF t = 2 OR (t = 1 AND i > 1) THEN
            'valid (continue)
        ELSE
            IF i = 1 THEN isvalidvariable = 0: EXIT FUNCTION
            EXIT FOR
        END IF
    NEXT

    isvalidvariable = 1
    IF i > n THEN EXIT FUNCTION 'i is always greater than n because n is undefined here. Why didn't I remove this line and the ones below it, which will never run? Cause I'm a coward. F.h.
    e$ = RIGHT$(a$, LEN(a$) - i - 1)
    IF e$ = "%%" OR e$ = "~%%" THEN EXIT FUNCTION
    IF e$ = "%" OR e$ = "~%" THEN EXIT FUNCTION
    IF e$ = "&" OR e$ = "~&" THEN EXIT FUNCTION
    IF e$ = "&&" OR e$ = "~&&" THEN EXIT FUNCTION
    IF e$ = "!" OR e$ = "#" OR e$ = "##" THEN EXIT FUNCTION
    IF e$ = "$" THEN EXIT FUNCTION
    IF e$ = "`" THEN EXIT FUNCTION
    IF LEFT$(e$, 1) <> "$" AND LEFT$(e$, 1) <> "`" THEN isvalidvariable = 0: EXIT FUNCTION
    e$ = RIGHT$(e$, LEN(e$) - 1)
    IF isuinteger(e$) THEN isvalidvariable = 1: EXIT FUNCTION
    isvalidvariable = 0
END FUNCTION

FUNCTION lineformat$ (a$)
    a2$ = ""
    linecontinuation = 0

    continueline:

    a$ = a$ + "  " 'add 2 extra spaces to make reading next char easier

    ca$ = a$
    a$ = UCASE$(a$)

    n = LEN(a$)
    i = 1
    lineformatnext:
    IF i >= n THEN GOTO lineformatdone

    c = ASC(a$, i)
    c$ = CHR$(c) '***remove later***

    '----------------quoted string----------------
    IF c = 34 THEN '"
        endingquote = INSTR(i + 1, ca$, CHR$(34))
        IF endingquote = 0 THEN endingquote = n - 1

        a2$ = a2$ + sp + createElementString$(MID$(ca$, i + 1, endingquote - 1 - i))
        i = endingquote + 1

        GOTO lineformatnext
    END IF

    '----------------number----------------
    firsti = i
    IF c = 46 THEN
        c2$ = MID$(a$, i + 1, 1): c2 = ASC(c2$)
        IF (c2 >= 48 AND c2 <= 57) THEN GOTO lfnumber
    END IF
    IF (c >= 48 AND c <= 57) THEN '0-9
        lfnumber:

        'handle 'IF a=1 THEN a=2 ELSE 100' by assuming numeric after ELSE to be a
        IF RIGHT$(a2$, 5) = sp + "ELSE" THEN
            a2$ = a2$ + sp + "GOTO"
        END IF

        'Number will be converted to the following format:
        ' 999999  .        99999  E        +         999
        '[whole$][dp(0/1)][frac$][ed(1/2)][pm(1/-1)][ex$]
        ' 0                1               2         3    <-mode

        mode = 0
        whole$ = ""
        dp = 0
        frac$ = ""
        ed = 0 'E=1, D=2, F=3
        pm = 1
        ex$ = ""




        lfreadnumber:
        valid = 0

        IF c = 46 THEN
            IF mode = 0 THEN valid = 1: dp = 1: mode = 1
        END IF

        IF c >= 48 AND c <= 57 THEN '0-9
            valid = 1
            IF mode = 0 THEN whole$ = whole$ + c$
            IF mode = 1 THEN frac$ = frac$ + c$
            IF mode = 2 THEN mode = 3
            IF mode = 3 THEN ex$ = ex$ + c$
        END IF

        IF c = 69 OR c = 68 OR c = 70 THEN 'E,D,F
            IF mode < 2 THEN
                valid = 1
                IF c = 69 THEN ed = 1
                IF c = 68 THEN ed = 2
                IF c = 70 THEN ed = 3
                mode = 2
            END IF
        END IF

        IF c = 43 OR c = 45 THEN '+,-
            IF mode = 2 THEN
                valid = 1
                IF c = 45 THEN pm = -1
                mode = 3
            END IF
        END IF

        IF valid THEN
            IF i <= n THEN i = i + 1: c$ = MID$(a$, i, 1): c = ASC(c$): GOTO lfreadnumber
        END IF



        'cull leading 0s off whole$
        DO WHILE LEFT$(whole$, 1) = "0": whole$ = RIGHT$(whole$, LEN(whole$) - 1): LOOP
        'cull trailing 0s off frac$
        DO WHILE RIGHT$(frac$, 1) = "0": frac$ = LEFT$(frac$, LEN(frac$) - 1): LOOP
        'cull leading 0s off ex$
        DO WHILE LEFT$(ex$, 1) = "0": ex$ = RIGHT$(ex$, LEN(ex$) - 1): LOOP

        IF dp <> 0 OR ed <> 0 THEN float = 1 ELSE float = 0

        extused = 1

        IF ed THEN e$ = "": GOTO lffoundext 'no extensions valid after E/D/F specified

        '3-character extensions
        IF i <= n - 2 THEN
            e$ = MID$(a$, i, 3)
            IF e$ = "~%%" AND float = 0 THEN i = i + 3: GOTO lffoundext
            IF e$ = "~&&" AND float = 0 THEN i = i + 3: GOTO lffoundext
            IF e$ = "~%&" AND float = 0 THEN Give_Error "Cannot use _OFFSET symbols after numbers": EXIT FUNCTION
        END IF
        '2-character extensions
        IF i <= n - 1 THEN
            e$ = MID$(a$, i, 2)
            IF e$ = "%%" AND float = 0 THEN i = i + 2: GOTO lffoundext
            IF e$ = "~%" AND float = 0 THEN i = i + 2: GOTO lffoundext
            IF e$ = "&&" AND float = 0 THEN i = i + 2: GOTO lffoundext
            IF e$ = "~&" AND float = 0 THEN i = i + 2: GOTO lffoundext
            IF e$ = "%&" AND float = 0 THEN Give_Error "Cannot use _OFFSET symbols after numbers": EXIT FUNCTION
            IF e$ = "##" THEN
                i = i + 2
                ed = 3
                e$ = ""
                GOTO lffoundext
            END IF
            IF e$ = "~`" THEN
                i = i + 2
                GOTO lffoundbitext
            END IF
        END IF
        '1-character extensions
        IF i <= n THEN
            e$ = MID$(a$, i, 1)
            IF e$ = "%" AND float = 0 THEN i = i + 1: GOTO lffoundext
            IF e$ = "&" AND float = 0 THEN i = i + 1: GOTO lffoundext
            IF e$ = "!" THEN
                i = i + 1
                ed = 1
                e$ = ""
                GOTO lffoundext
            END IF
            IF e$ = "#" THEN
                i = i + 1
                ed = 2
                e$ = ""
                GOTO lffoundext
            END IF
            IF e$ = "`" THEN
                i = i + 1
                lffoundbitext:
                bitn$ = ""
                DO WHILE i <= n
                    c2 = ASC(MID$(a$, i, 1))
                    IF c2 >= 48 AND c2 <= 57 THEN
                        bitn$ = bitn$ + CHR$(c2)
                        i = i + 1
                    ELSE
                        EXIT DO
                    END IF
                LOOP
                IF bitn$ = "" THEN bitn$ = "1"
                'cull leading 0s off bitn$
                DO WHILE LEFT$(bitn$, 1) = "0": bitn$ = RIGHT$(bitn$, LEN(bitn$) - 1): LOOP
                e$ = e$ + bitn$
                GOTO lffoundext
            END IF
        END IF

        IF float THEN 'floating point types CAN be assumed
            'calculate first significant digit offset & number of significant digits
            IF whole$ <> "" THEN
                offset = LEN(whole$) - 1
                sigdigits = LEN(whole$) + LEN(frac$)
            ELSE
                IF frac$ <> "" THEN
                    offset = -1
                    sigdigits = LEN(frac$)
                    FOR i2 = 1 TO LEN(frac$)
                        IF MID$(frac$, i2, 1) <> "0" THEN EXIT FOR
                        offset = offset - 1
                        sigdigits = sigdigits - 1
                    NEXT
                ELSE
                    'number is 0
                    offset = 0
                    sigdigits = 0
                END IF
            END IF
            sigdig$ = RIGHT$(whole$ + frac$, sigdigits)
            'SINGLE?
            IF sigdigits <= 7 THEN 'QBASIC interprets anything with more than 7 sig. digits as a DOUBLE
                IF offset <= 38 AND offset >= -38 THEN 'anything outside this range cannot be represented as a SINGLE
                    IF offset = 38 THEN
                        IF sigdig$ > "3402823" THEN GOTO lfxsingle
                    END IF
                    IF offset = -38 THEN
                        IF sigdig$ < "1175494" THEN GOTO lfxsingle
                    END IF
                    ed = 1
                    e$ = ""
                    GOTO lffoundext
                END IF
            END IF
            lfxsingle:
            'DOUBLE?
            IF sigdigits <= 16 THEN 'QB64 handles DOUBLES with 16-digit precision
                IF offset <= 308 AND offset >= -308 THEN 'anything outside this range cannot be represented as a DOUBLE
                    IF offset = 308 THEN
                        IF sigdig$ > "1797693134862315" THEN GOTO lfxdouble
                    END IF
                    IF offset = -308 THEN
                        IF sigdig$ < "2225073858507201" THEN GOTO lfxdouble
                    END IF
                    ed = 2
                    e$ = ""
                    GOTO lffoundext
                END IF
            END IF
            lfxdouble:
            'assume _FLOAT
            ed = 3
            e$ = "": GOTO lffoundext
        END IF

        extused = 0
        e$ = ""
        lffoundext:

        'make sure a leading numberic character exists
        IF whole$ = "" THEN whole$ = "0"
        'if a float, ensure frac$<>"" and dp=1
        IF float THEN
            dp = 1
            IF frac$ = "" THEN frac$ = "0"
        END IF
        'if ed is specified, make sure ex$ exists
        IF ed <> 0 AND ex$ = "" THEN ex$ = "0"

        a2$ = a2$ + sp
        a2$ = a2$ + whole$
        IF dp THEN a2$ = a2$ + "." + frac$
        IF ed THEN
            IF ed = 1 THEN a2$ = a2$ + "E"
            IF ed = 2 THEN a2$ = a2$ + "D"
            IF ed = 3 THEN a2$ = a2$ + "F"
            IF pm = -1 AND ex$ <> "0" THEN a2$ = a2$ + "-" ELSE a2$ = a2$ + "+"
            a2$ = a2$ + ex$
        END IF
        a2$ = a2$ + e$

        IF extused THEN a2$ = a2$ + "," + MID$(a$, firsti, i - firsti)

        GOTO lineformatnext
    END IF

    '----------------(number)&H...----------------
    'note: the final value, not the number of hex characters, sets the default type
    IF c = 38 THEN '&
        IF MID$(a$, i + 1, 1) = "H" THEN
            i = i + 2
            hx$ = ""
            lfreadhex:
            IF i <= n THEN
                c$ = MID$(a$, i, 1): c = ASC(c$)
                IF (c >= 48 AND c <= 57) OR (c >= 65 AND c <= 70) THEN hx$ = hx$ + c$: i = i + 1: GOTO lfreadhex
            END IF
            fullhx$ = "&H" + hx$

            'cull leading 0s off hx$
            DO WHILE LEFT$(hx$, 1) = "0": hx$ = RIGHT$(hx$, LEN(hx$) - 1): LOOP
            IF hx$ = "" THEN hx$ = "0"

            bitn$ = ""
            '3-character extensions
            IF i <= n - 2 THEN
                e$ = MID$(a$, i, 3)
                IF e$ = "~%%" THEN i = i + 3: GOTO lfhxext
                IF e$ = "~&&" THEN i = i + 3: GOTO lfhxext
                IF e$ = "~%&" THEN Give_Error "Cannot use _OFFSET symbols after numbers": EXIT FUNCTION
            END IF
            '2-character extensions
            IF i <= n - 1 THEN
                e$ = MID$(a$, i, 2)
                IF e$ = "%%" THEN i = i + 2: GOTO lfhxext
                IF e$ = "~%" THEN i = i + 2: GOTO lfhxext
                IF e$ = "&&" THEN i = i + 2: GOTO lfhxext
                IF e$ = "%&" THEN Give_Error "Cannot use _OFFSET symbols after numbers": EXIT FUNCTION
                IF e$ = "~&" THEN i = i + 2: GOTO lfhxext
                IF e$ = "~`" THEN
                    i = i + 2
                    GOTO lfhxbitext
                END IF
            END IF
            '1-character extensions
            IF i <= n THEN
                e$ = MID$(a$, i, 1)
                IF e$ = "%" THEN i = i + 1: GOTO lfhxext
                IF e$ = "&" THEN i = i + 1: GOTO lfhxext
                IF e$ = "`" THEN
                    i = i + 1
                    lfhxbitext:
                    DO WHILE i <= n
                        c2 = ASC(MID$(a$, i, 1))
                        IF c2 >= 48 AND c2 <= 57 THEN
                            bitn$ = bitn$ + CHR$(c2)
                            i = i + 1
                        ELSE
                            EXIT DO
                        END IF
                    LOOP
                    IF bitn$ = "" THEN bitn$ = "1"
                    'cull leading 0s off bitn$
                    DO WHILE LEFT$(bitn$, 1) = "0": bitn$ = RIGHT$(bitn$, LEN(bitn$) - 1): LOOP
                    GOTO lfhxext
                END IF
            END IF
            'if no valid extension context was given, assume one
            'note: leading 0s have been culled, so LEN(hx$) reflects its values size
            e$ = "&&"
            IF LEN(hx$) <= 8 THEN e$ = "&" 'as in QBASIC, signed values must be used
            IF LEN(hx$) <= 4 THEN e$ = "%" 'as in QBASIC, signed values must be used
            GOTO lfhxext2
            lfhxext:
            fullhx$ = fullhx$ + e$ + bitn$
            lfhxext2:

            'build 8-byte unsigned integer rep. of hx$
            IF LEN(hx$) > 16 THEN Give_Error "Overflow": EXIT FUNCTION
            v~&& = 0
            FOR i2 = 1 TO LEN(hx$)
                v2 = ASC(MID$(hx$, i2, 1))
                IF v2 <= 57 THEN v2 = v2 - 48 ELSE v2 = v2 - 65 + 10
                v~&& = v~&& * 16 + v2
            NEXT

            finishhexoctbin:
            num$ = _TOSTR$(v~&&) 'correct for unsigned values (overflow of unsigned can be checked later)
            IF LEFT$(e$, 1) <> "~" THEN 'note: range checking will be performed later in fixop.order
                'signed

                IF e$ = "%%" THEN
                    IF v~&& > 127 THEN
                        IF v~&& > 255 THEN Give_Error "Overflow": EXIT FUNCTION
                        v~&& = ((NOT v~&&) AND 255) + 1
                        num$ = "-" + sp + _TOSTR$(v~&&)
                    END IF
                END IF

                IF e$ = "%" THEN
                    IF v~&& > 32767 THEN
                        IF v~&& > 65535 THEN Give_Error "Overflow": EXIT FUNCTION
                        v~&& = ((NOT v~&&) AND 65535) + 1
                        num$ = "-" + sp + _TOSTR$(v~&&)
                    END IF
                END IF

                IF e$ = "&" THEN
                    IF v~&& > 2147483647 THEN
                        IF v~&& > 4294967295 THEN Give_Error "Overflow": EXIT FUNCTION
                        v~&& = ((NOT v~&&) AND 4294967295) + 1
                        num$ = "-" + sp + _TOSTR$(v~&&)
                    END IF
                END IF

                IF e$ = "&&" THEN
                    IF v~&& > 9223372036854775807 THEN
                        'note: no error checking necessary
                        v~&& = (NOT v~&&) + 1
                        num$ = "-" + sp + _TOSTR$(v~&&)
                    END IF
                END IF

                IF e$ = "`" THEN
                    vbitn = VAL(bitn$)
                    h~&& = 1: FOR i2 = 1 TO vbitn - 1: h~&& = h~&& * 2: NEXT: h~&& = h~&& - 1 'build h~&&
                    IF v~&& > h~&& THEN
                        h~&& = 1: FOR i2 = 1 TO vbitn: h~&& = h~&& * 2: NEXT: h~&& = h~&& - 1 'build h~&&
                        IF v~&& > h~&& THEN Give_Error "Overflow": EXIT FUNCTION
                        v~&& = ((NOT v~&&) AND h~&&) + 1
                        num$ = "-" + sp + _TOSTR$(v~&&)
                    END IF
                END IF

            END IF '<>"~"

            a2$ = a2$ + sp + num$ + e$ + bitn$ + "," + fullhx$

            GOTO lineformatnext
        END IF
    END IF

    '----------------(number)&O...----------------
    'note: the final value, not the number of oct characters, sets the default type
    IF c = 38 THEN '&
        IF MID$(a$, i + 1, 1) = "O" THEN
            i = i + 2
            'note: to avoid mistakes, hx$ is used instead of 'ot$'
            hx$ = ""
            lfreadoct:
            IF i <= n THEN
                c$ = MID$(a$, i, 1): c = ASC(c$)
                IF c >= 48 AND c <= 55 THEN hx$ = hx$ + c$: i = i + 1: GOTO lfreadoct
            END IF
            fullhx$ = "&O" + hx$

            'cull leading 0s off hx$
            DO WHILE LEFT$(hx$, 1) = "0": hx$ = RIGHT$(hx$, LEN(hx$) - 1): LOOP
            IF hx$ = "" THEN hx$ = "0"

            bitn$ = ""
            '3-character extensions
            IF i <= n - 2 THEN
                e$ = MID$(a$, i, 3)
                IF e$ = "~%%" THEN i = i + 3: GOTO lfotext
                IF e$ = "~&&" THEN i = i + 3: GOTO lfotext
                IF e$ = "~%&" THEN Give_Error "Cannot use _OFFSET symbols after numbers": EXIT FUNCTION
            END IF
            '2-character extensions
            IF i <= n - 1 THEN
                e$ = MID$(a$, i, 2)
                IF e$ = "%%" THEN i = i + 2: GOTO lfotext
                IF e$ = "~%" THEN i = i + 2: GOTO lfotext
                IF e$ = "&&" THEN i = i + 2: GOTO lfotext
                IF e$ = "%&" THEN Give_Error "Cannot use _OFFSET symbols after numbers": EXIT FUNCTION
                IF e$ = "~&" THEN i = i + 2: GOTO lfotext
                IF e$ = "~`" THEN
                    i = i + 2
                    GOTO lfotbitext
                END IF
            END IF
            '1-character extensions
            IF i <= n THEN
                e$ = MID$(a$, i, 1)
                IF e$ = "%" THEN i = i + 1: GOTO lfotext
                IF e$ = "&" THEN i = i + 1: GOTO lfotext
                IF e$ = "`" THEN
                    i = i + 1
                    lfotbitext:
                    bitn$ = ""
                    DO WHILE i <= n
                        c2 = ASC(MID$(a$, i, 1))
                        IF c2 >= 48 AND c2 <= 57 THEN
                            bitn$ = bitn$ + CHR$(c2)
                            i = i + 1
                        ELSE
                            EXIT DO
                        END IF
                    LOOP
                    IF bitn$ = "" THEN bitn$ = "1"
                    'cull leading 0s off bitn$
                    DO WHILE LEFT$(bitn$, 1) = "0": bitn$ = RIGHT$(bitn$, LEN(bitn$) - 1): LOOP
                    GOTO lfotext
                END IF
            END IF
            'if no valid extension context was given, assume one
            'note: leading 0s have been culled, so LEN(hx$) reflects its values size
            e$ = "&&"
            '37777777777
            IF LEN(hx$) <= 11 THEN
                IF LEN(hx$) < 11 OR ASC(LEFT$(hx$, 1)) <= 51 THEN e$ = "&"
            END IF
            '177777
            IF LEN(hx$) <= 6 THEN
                IF LEN(hx$) < 6 OR LEFT$(hx$, 1) = "1" THEN e$ = "%"
            END IF

            GOTO lfotext2
            lfotext:
            fullhx$ = fullhx$ + e$ + bitn$
            lfotext2:

            'build 8-byte unsigned integer rep. of hx$
            '1777777777777777777777 (22 digits)
            IF LEN(hx$) > 22 THEN Give_Error "Overflow": EXIT FUNCTION
            IF LEN(hx$) = 22 THEN
                IF LEFT$(hx$, 1) <> "1" THEN Give_Error "Overflow": EXIT FUNCTION
            END IF
            '********change v& to v~&&********
            v~&& = 0
            FOR i2 = 1 TO LEN(hx$)
                v2 = ASC(MID$(hx$, i2, 1))
                v2 = v2 - 48
                v~&& = v~&& * 8 + v2
            NEXT

            GOTO finishhexoctbin
        END IF
    END IF

    '----------------(number)&B...----------------
    'note: the final value, not the number of bin characters, sets the default type
    IF c = 38 THEN '&
        IF MID$(a$, i + 1, 1) = "B" THEN
            i = i + 2
            'note: to avoid mistakes, hx$ is used instead of 'bi$'
            hx$ = ""
            lfreadbin:
            IF i <= n THEN
                c$ = MID$(a$, i, 1): c = ASC(c$)
                IF c >= 48 AND c <= 49 THEN hx$ = hx$ + c$: i = i + 1: GOTO lfreadbin
            END IF
            fullhx$ = "&B" + hx$

            'cull leading 0s off hx$
            DO WHILE LEFT$(hx$, 1) = "0": hx$ = RIGHT$(hx$, LEN(hx$) - 1): LOOP
            IF hx$ = "" THEN hx$ = "0"

            bitn$ = ""
            '3-character extensions
            IF i <= n - 2 THEN
                e$ = MID$(a$, i, 3)
                IF e$ = "~%%" THEN i = i + 3: GOTO lfbiext
                IF e$ = "~&&" THEN i = i + 3: GOTO lfbiext
                IF e$ = "~%&" THEN Give_Error "Cannot use _OFFSET symbols after numbers": EXIT FUNCTION
            END IF
            '2-character extensions
            IF i <= n - 1 THEN
                e$ = MID$(a$, i, 2)
                IF e$ = "%%" THEN i = i + 2: GOTO lfbiext
                IF e$ = "~%" THEN i = i + 2: GOTO lfbiext
                IF e$ = "&&" THEN i = i + 2: GOTO lfbiext
                IF e$ = "%&" THEN Give_Error "Cannot use _OFFSET symbols after numbers": EXIT FUNCTION
                IF e$ = "~&" THEN i = i + 2: GOTO lfbiext
                IF e$ = "~`" THEN
                    i = i + 2
                    GOTO lfbibitext
                END IF
            END IF


            '1-character extensions
            IF i <= n THEN
                e$ = MID$(a$, i, 1)
                IF e$ = "%" THEN i = i + 1: GOTO lfbiext
                IF e$ = "&" THEN i = i + 1: GOTO lfbiext
                IF e$ = "`" THEN
                    i = i + 1
                    lfbibitext:
                    bitn$ = ""
                    DO WHILE i <= n
                        c2 = ASC(MID$(a$, i, 1))
                        IF c2 >= 48 AND c2 <= 57 THEN
                            bitn$ = bitn$ + CHR$(c2)
                            i = i + 1
                        ELSE
                            EXIT DO
                        END IF
                    LOOP
                    IF bitn$ = "" THEN bitn$ = "1"
                    'cull leading 0s off bitn$
                    DO WHILE LEFT$(bitn$, 1) = "0": bitn$ = RIGHT$(bitn$, LEN(bitn$) - 1): LOOP
                    GOTO lfbiext
                END IF
            END IF
            'if no valid extension context was given, assume one
            'note: leading 0s have been culled, so LEN(hx$) reflects its values size
            e$ = "&&"
            IF LEN(hx$) <= 32 THEN e$ = "&"
            IF LEN(hx$) <= 16 THEN e$ = "%"

            GOTO lfbiext2
            lfbiext:
            fullhx$ = fullhx$ + e$ + bitn$
            lfbiext2:

            'build 8-byte unsigned integer rep. of hx$
            IF LEN(hx$) > 64 THEN Give_Error "Overflow": EXIT FUNCTION

            v~&& = 0
            FOR i2 = 1 TO LEN(hx$)
                v2 = ASC(MID$(hx$, i2, 1))
                v2 = v2 - 48
                v~&& = v~&& * 2 + v2
            NEXT

            GOTO finishhexoctbin
        END IF
    END IF


    '----------------(number)&H??? error----------------
    IF c = 38 THEN Give_Error "Expected &H... or &O...": EXIT FUNCTION

    '----------------variable/name----------------
    '*trailing _ is treated as a separate line extension*
    IF (c >= 65 AND c <= 90) OR c = 95 THEN 'A-Z(a-z) or _
        IF c = 95 THEN p2 = 0 ELSE p2 = i
        FOR i2 = i + 1 TO n
            c2 = ASC(a$, i2)
            IF NOT alphanumeric(c2) THEN EXIT FOR
            IF c2 <> 95 THEN p2 = i2
        NEXT
        IF p2 THEN 'not just underscores!
            'char is from i to p2
            n2 = p2 - i + 1
            a3$ = MID$(a$, i, n2)

            '----(variable/name)rem----
            IF n2 = 3 THEN
                IF a3$ = "REM" THEN
                    i = i + n2
                    IF i < n THEN
                        c = ASC(a$, i)
                        IF c = 46 THEN a2$ = a2$ + sp + MID$(ca$, i - n2, n2): GOTO extcheck 'rem.Variable is a valid variable name in QB45
                    END IF

                    'note: In QBASIC 'IF cond THEN REM comment' counts as a single line IF statement, however use of ' instead of REM does not
                    IF UCASE$(RIGHT$(a2$, 5)) = sp + "THEN" THEN a2$ = a2$ + sp + "'" 'add nop
                    layoutcomment$ = SCase$("Rem")
                    GOTO comment
                END IF
            END IF

            '----(variable/name)data----
            IF n2 = 4 THEN
                IF a3$ = "DATA" THEN
                    x$ = ""
                    i = i + n2
                    IF i < n THEN
                        c = ASC(a$, i)
                        IF c = 46 THEN a2$ = a2$ + sp + MID$(ca$, i - n2, n2): GOTO extcheck 'data.Variable is a valid variable name in QB45
                    END IF

                    scan = 0
                    speechmarks = 0
                    commanext = 0
                    finaldata = 0
                    e$ = ""
                    p1 = 0
                    p2 = 0
                    nextdatachr:
                    IF i < n THEN
                        c = ASC(a$, i)
                        IF c = 9 OR c = 32 THEN
                            IF scan = 0 THEN GOTO skipwhitespace
                        END IF

                        IF c = 58 THEN '":"
                            IF speechmarks = 0 THEN finaldata = 1: GOTO adddata
                        END IF

                        IF c = 44 THEN '","
                            IF speechmarks = 0 THEN
                                adddata:
                                IF prepass = 0 THEN
                                    IF p1 THEN
                                        'FOR i2 = p1 TO p2
                                        '    DATA_add ASC(ca$, i2)
                                        'NEXT
                                        x$ = x$ + MID$(ca$, p1, p2 - p1 + 1)
                                    END IF
                                    'assume closing "
                                    IF speechmarks THEN
                                        'DATA_add 34
                                        x$ = x$ + CHR$(34)
                                    END IF
                                    'append comma
                                    'DATA_add 44
                                    x$ = x$ + CHR$(44)
                                END IF
                                IF finaldata = 1 THEN GOTO finisheddata
                                e$ = ""
                                p1 = 0
                                p2 = 0
                                speechmarks = 0
                                scan = 0
                                commanext = 0
                                i = i + 1
                                GOTO nextdatachr
                            END IF
                        END IF '","

                        IF commanext = 1 THEN
                            IF c <> 32 AND c <> 9 THEN Give_Error "Expected , after quoted string in DATA statement": EXIT FUNCTION
                        END IF

                        IF c = 34 THEN
                            IF speechmarks = 1 THEN
                                commanext = 1
                                speechmarks = 0
                            END IF
                            IF scan = 0 THEN speechmarks = 1
                        END IF

                        scan = 1

                        IF p1 = 0 THEN p1 = i: p2 = i
                        IF c <> 9 AND c <> 32 THEN p2 = i

                        skipwhitespace:
                        i = i + 1: GOTO nextdatachr
                    END IF 'i<n
                    finaldata = 1: GOTO adddata
                    finisheddata:
                    e$ = ""
                    IF prepass = 0 THEN
                        WriteBufRawData DataBinBuf, x$
                        DataOffset = DataOffset + LEN(x$)

                        e$ = SPACE$((LEN(x$) - 1) * 2)
                        FOR ec = 1 TO LEN(x$) - 1
                            '2 chr hex encode each character
                            v1 = ASC(x$, ec)
                            v2 = v1 \ 16: IF v2 <= 9 THEN v2 = v2 + 48 ELSE v2 = v2 + 55
                            v1 = v1 AND 15: IF v1 <= 9 THEN v1 = v1 + 48 ELSE v1 = v1 + 55
                            ASC(e$, ec * 2 - 1) = v1
                            ASC(e$, ec * 2) = v2
                        NEXT

                    END IF

                    a2$ = a2$ + sp + "DATA": IF LEN(e$) THEN a2$ = a2$ + sp + "_" + e$
                    GOTO lineformatnext
                END IF
            END IF

            a2$ = a2$ + sp + MID$(ca$, i, n2)
            i = i + n2

            '----(variable/name)extensions----
            extcheck:
            IF n2 > 40 THEN Give_Error "Identifier longer than 40 character limit": EXIT FUNCTION
            c3 = ASC(a$, i)
            m = 0
            IF c3 = 126 THEN '"~"
                e2$ = MID$(a$, i + 1, 2)
                IF e2$ = "&&" THEN e2$ = "~&&": GOTO lfgetve
                IF e2$ = "%%" THEN e2$ = "~%%": GOTO lfgetve
                IF e2$ = "%&" THEN e2$ = "~%&": GOTO lfgetve
                e2$ = CHR$(ASC(e2$))
                IF e2$ = "&" THEN e2$ = "~&": GOTO lfgetve
                IF e2$ = "%" THEN e2$ = "~%": GOTO lfgetve
                IF e2$ = "`" THEN m = 1: e2$ = "~`": GOTO lfgetve
            END IF
            IF c3 = 37 THEN
                c4 = ASC(a$, i + 1)
                IF c4 = 37 THEN e2$ = "%%": GOTO lfgetve
                IF c4 = 38 THEN e2$ = "%&": GOTO lfgetve
                e2$ = "%": GOTO lfgetve
            END IF
            IF c3 = 38 THEN
                c4 = ASC(a$, i + 1)
                IF c4 = 38 THEN e2$ = "&&": GOTO lfgetve
                e2$ = "&": GOTO lfgetve
            END IF
            IF c3 = 33 THEN e2$ = "!": GOTO lfgetve
            IF c3 = 35 THEN
                c4 = ASC(a$, i + 1)
                IF c4 = 35 THEN e2$ = "##": GOTO lfgetve
                e2$ = "#": GOTO lfgetve
            END IF
            IF c3 = 36 THEN m = 1: e2$ = "$": GOTO lfgetve
            IF c3 = 96 THEN m = 1: e2$ = "`": GOTO lfgetve
            '(no symbol)

            'cater for unusual names/labels (eg a.0b%)
            IF ASC(a$, i) = 46 THEN '"."
                c2 = ASC(a$, i + 1)
                IF c2 >= 48 AND c2 <= 57 THEN
                    'scan until no further alphanumerics
                    p2 = i + 1
                    FOR i2 = i + 2 TO n
                        c = ASC(a$, i2)

                        IF NOT alphanumeric(c) THEN EXIT FOR
                        IF c <> 95 THEN p2 = i2 'don't including trailing _
                    NEXT
                    a2$ = a2$ + sp + "." + sp + MID$(ca$, i + 1, p2 - (i + 1) + 1) 'case sensitive
                    n2 = n2 + 1 + (p2 - (i + 1) + 1)
                    i = p2 + 1
                    GOTO extcheck 'it may have an extension or be continued with another "."
                END IF
            END IF

            GOTO lineformatnext

            lfgetve:
            i = i + LEN(e2$)
            a2$ = a2$ + e2$
            IF m THEN 'allow digits after symbol
                lfgetvd:
                IF i < n THEN
                    c = ASC(a$, i)
                    IF c >= 48 AND c <= 57 THEN a2$ = a2$ + CHR$(c): i = i + 1: GOTO lfgetvd
                END IF
            END IF 'm

            GOTO lineformatnext

        END IF 'p2
    END IF 'variable/name
    '----------------variable/name end----------------

    '----------------spacing----------------
    IF c = 32 OR c = 9 THEN i = i + 1: GOTO lineformatnext

    '----------------symbols----------------
    '--------single characters--------
    IF lfsinglechar(c) THEN
        IF (c = 60) OR (c = 61) OR (c = 62) THEN
            count = 0
            DO
                count = count + 1
                IF i + count >= LEN(a$) - 2 THEN EXIT DO
            LOOP UNTIL ASC(a$, i + count) <> 32
            c2 = ASC(a$, i + count)
            IF c = 60 THEN '<
                IF c2 = 61 THEN a2$ = a2$ + sp + "<=": i = i + count + 1: GOTO lineformatnext
                IF c2 = 62 THEN a2$ = a2$ + sp + "<>": i = i + count + 1: GOTO lineformatnext
            ELSEIF c = 62 THEN '>
                IF c2 = 61 THEN a2$ = a2$ + sp + ">=": i = i + count + 1: GOTO lineformatnext
                IF c2 = 60 THEN a2$ = a2$ + sp + "<>": i = i + count + 1: GOTO lineformatnext '>< to <>
            ELSEIF c = 61 THEN '=
                IF c2 = 62 THEN a2$ = a2$ + sp + ">=": i = i + count + 1: GOTO lineformatnext '=> to >=
                IF c2 = 60 THEN a2$ = a2$ + sp + "<=": i = i + count + 1: GOTO lineformatnext '=< to <=
            END IF
        END IF

        IF c = 36 AND LEN(a2$) THEN GOTO badusage '$


        a2$ = a2$ + sp + CHR$(c)
        i = i + 1
        GOTO lineformatnext
    END IF
    badusage:

    IF c <> 39 THEN Give_Error "Unexpected character on line": EXIT FUNCTION 'invalid symbol encountered

    '----------------comment(')----------------
    layoutcomment$ = "'"
    i = i + 1
    comment:
    IF i >= n THEN GOTO lineformatdone2
    c$ = RIGHT$(a$, LEN(a$) - i + 1)
    cc$ = RIGHT$(ca$, LEN(ca$) - i + 1)
    IF LEN(c$) = 0 THEN GOTO lineformatdone2
    layoutcomment$ = RTRIM$(layoutcomment$ + cc$)

    c$ = _TRIM$(c$)
    IF LEN(c$) = 0 THEN GOTO lineformatdone2
    ac = ASC(c$): cdif = LEN(layoutcomment$) - LEN(c$)
    'note: any non-whitespace character between the comment leader and the
    '      first '$' renders this a plain comment
    '    : the leading '$' does NOT have to be part of a valid metacommand.
    '      E.g., REM $FOO $DYNAMIC is a valid metacommand line
    IF ac <> 36 THEN GOTO lineformatdone2
    nocasec$ = LTRIM$(RIGHT$(ca$, LEN(ca$) - i + 1))
    memmode = 0
    x = 1
    DO
        'note: metacommands may appear on a line any number of times but only
        '      the last appearance of $INCLUDE, and either $STATIC or $DYNAMIC,
        '      is processed
        '    : metacommands do not need to be terminated by word boundaries.
        '      E.g., $STATICanychars$DYNAMIC is valid

        IF MID$(c$, x, 11) = "$FORMAT:OFF" THEN
            MID$(layoutcomment$, x + cdif, 11) = SCase$("$Format:Off")
            IDEAutoIndent = 0: IDEAutoLayout = 0
        ELSEIF MID$(c$, x, 10) = "$FORMAT:ON" THEN
            MID$(layoutcomment$, x + cdif, 10) = SCase$("$Format:On")
            IDEAutoIndent = DEFAutoIndent: IDEAutoLayout = DEFAutoLayout

        ELSEIF MID$(c$, x, 7) = "$STATIC" THEN
            MID$(layoutcomment$, x + cdif, 7) = SCase$("$Static")
            memmode = 1
        ELSEIF MID$(c$, x, 8) = "$DYNAMIC" THEN
            MID$(layoutcomment$, x + cdif, 8) = SCase$("$Dynamic")
            memmode = 2
        ELSEIF MID$(c$, x, 8) = "$INCLUDE" AND MID$(c$, x + 8, 4) <> "ONCE" THEN
            MID$(layoutcomment$, x + cdif, 8) = SCase$("$Include")
            'note: INCLUDE adds the file AFTER the line it is on has been processed
            'skip spaces until :
            FOR xx = x + 8 TO LEN(c$)
                ac = ASC(MID$(c$, xx, 1))
                IF ac = 58 THEN EXIT FOR ':
                IF ac <> 32 AND ac <> 9 THEN Give_Error "Expected $INCLUDE:'filename'": EXIT FUNCTION
            NEXT
            x = xx
            'skip spaces until '
            FOR xx = x + 1 TO LEN(c$)
                ac = ASC(MID$(c$, xx, 1))
                IF ac = 39 THEN EXIT FOR 'character:'
                IF ac <> 32 AND ac <> 9 THEN Give_Error "Expected $INCLUDE:'filename'": EXIT FUNCTION
            NEXT
            x = xx
            xx = INSTR(x + 1, c$, "'")
            IF xx = 0 THEN Give_Error "Expected $INCLUDE:'filename'": EXIT FUNCTION
            addmetainclude$ = MID$(nocasec$, x + 1, xx - x - 1)
            IF addmetainclude$ = "" THEN Give_Error "Expected $INCLUDE:'filename'": EXIT FUNCTION
        END IF

        x = INSTR(x + 1, c$, "$")
    LOOP WHILE x <> 0

    IF memmode = 1 THEN addmetastatic = 1
    IF memmode = 2 THEN addmetadynamic = 1

    GOTO lineformatdone2



    lineformatdone:

    'line continuation?
    'note: line continuation in idemode is illegal
    IF LEN(a2$) THEN
        IF RIGHT$(a2$, 1) = "_" THEN

            linecontinuation = 1 'avoids auto-format glitches
            layout$ = ""

            'remove _ from the end of the building string
            IF LEN(a2$) >= 2 THEN
                IF RIGHT$(a2$, 2) = sp + "_" THEN a2$ = LEFT$(a2$, LEN(a2$) - 1)
            END IF
            a2$ = LEFT$(a2$, LEN(a2$) - 1)

            IF inclevel THEN
                fh = 199 + inclevel
                IF EOF(fh) THEN GOTO lineformatdone2
                LINE INPUT #fh, a$
                inclinenumber(inclevel) = inclinenumber(inclevel) + 1
                GOTO includecont 'note: should not increase linenumber
            END IF

            IF idemode THEN
                idecommand$ = CHR$(100)
                ignore = ide(0)
                ideerror = 0
                a$ = idereturn$
                IF a$ = "" THEN GOTO lineformatdone2
            ELSE
                a$ = lineinput3$
                IF a$ = CHR$(13) THEN GOTO lineformatdone2
                layoutcontinuations = layoutcontinuations + NATIVE_LINEENDING + a$
            END IF

            linenumber = linenumber + 1

            includecont:

            contline = 1
            GOTO continueline
        END IF
    END IF

    lineformatdone2:
    IF LEFT$(a2$, 1) = sp THEN a2$ = RIGHT$(a2$, LEN(a2$) - 1)

    'fix for trailing : error
    IF RIGHT$(a2$, 1) = ":" THEN a2$ = a2$ + sp + "'" 'add nop

    IF Debug THEN PRINT #9, "lineformat():return:" + a2$
    IF Error_Happened THEN EXIT FUNCTION
    lineformat$ = a2$

END FUNCTION


SUB makeidrefer (ref$, typ AS LONG)
    ref$ = _TOSTR$(currentid)
    typ = id.t + ISREFERENCE
END SUB

FUNCTION operatorusage (operator$, typ AS LONG, info$, lhs AS LONG, rhs AS LONG, result AS LONG)
    lhs = 7: rhs = 7: result = 0
    'return values
    '1 = use info$ as the operator without any other changes
    '2 = use the function returned in info$ to apply this operator
    '    upon left and right side of equation
    '3=  bracket left and right side with negation and change operator to info$
    '4=  BINARY NOT l.h.s, then apply operator in info$
    '5=  UNARY, bracket up rhs, apply operator info$ to left, rebracket again
    '6=  UNARY, bracket up rhs, apply operator info$ to left, rebracket, negate, rebracket again

    'lhs & rhs bit-field values
    '1=integeral
    '2=floating point
    '4=string
    '8=bool

    'string operator
    IF (typ AND ISSTRING) THEN
        lhs = 4: rhs = 4
        result = 4
        IF operator$ = "+" THEN info$ = "qbs_add": operatorusage = 2: EXIT FUNCTION
        result = 8
        IF operator$ = "=" THEN info$ = "qbs_equal": operatorusage = 2: EXIT FUNCTION
        IF operator$ = "<>" THEN info$ = "qbs_notequal": operatorusage = 2: EXIT FUNCTION
        IF operator$ = ">" THEN info$ = "qbs_greaterthan": operatorusage = 2: EXIT FUNCTION
        IF operator$ = "<" THEN info$ = "qbs_lessthan": operatorusage = 2: EXIT FUNCTION
        IF operator$ = ">=" THEN info$ = "qbs_greaterorequal": operatorusage = 2: EXIT FUNCTION
        IF operator$ = "<=" THEN info$ = "qbs_lessorequal": operatorusage = 2: EXIT FUNCTION
        IF Debug THEN PRINT #9, "INVALID STRING OPERATOR!": END
    END IF

    'assume numeric operator
    lhs = 1 + 2: rhs = 1 + 2
    IF operator$ = "^" THEN result = 2: info$ = "pow2": operatorusage = 2: EXIT FUNCTION
    IF operator$ = CHR$(241) THEN info$ = "-": operatorusage = 5: EXIT FUNCTION
    IF operator$ = "/" THEN
        info$ = "/ ": operatorusage = 1
        'for / division, either the lhs or the rhs must be a float to make
        'c++ return a result in floating point form
        IF (typ AND ISFLOAT) THEN
            'lhs is a float
            lhs = 2
            rhs = 1 + 2
        ELSE
            'lhs isn't a float!
            lhs = 1 + 2
            rhs = 2
        END IF
        result = 2
        EXIT FUNCTION
    END IF
    IF operator$ = "*" THEN info$ = "*": operatorusage = 1: EXIT FUNCTION
    IF operator$ = "+" THEN info$ = "+": operatorusage = 1: EXIT FUNCTION
    IF operator$ = "-" THEN info$ = "-": operatorusage = 1: EXIT FUNCTION

    result = 8
    IF operator$ = "=" THEN info$ = "==": operatorusage = 3: EXIT FUNCTION
    IF operator$ = ">" THEN info$ = ">": operatorusage = 3: EXIT FUNCTION
    IF operator$ = "<" THEN info$ = "<": operatorusage = 3: EXIT FUNCTION
    IF operator$ = "<>" THEN info$ = "!=": operatorusage = 3: EXIT FUNCTION
    IF operator$ = "<=" THEN info$ = "<=": operatorusage = 3: EXIT FUNCTION
    IF operator$ = ">=" THEN info$ = ">=": operatorusage = 3: EXIT FUNCTION

    lhs = 1: rhs = 1: result = 1
    operator$ = UCASE$(operator$)
    IF operator$ = "MOD" THEN info$ = "qb_safe_mod": operatorusage = 2: EXIT FUNCTION
    IF operator$ = "\" THEN info$ = "qb_safe_idiv": operatorusage = 2: EXIT FUNCTION
    IF operator$ = "IMP" THEN info$ = "|": operatorusage = 4: EXIT FUNCTION
    IF operator$ = "EQV" THEN info$ = "^": operatorusage = 4: EXIT FUNCTION
    IF operator$ = "XOR" THEN info$ = "^": operatorusage = 1: EXIT FUNCTION
    IF operator$ = "OR" THEN info$ = "|": operatorusage = 1: EXIT FUNCTION
    IF operator$ = "AND" THEN info$ = "&": operatorusage = 1: EXIT FUNCTION
    IF operator$ = "_ORELSE" THEN info$ = "||": operatorusage = 3: EXIT FUNCTION
    IF operator$ = "_ANDALSO" THEN info$ = "&&": operatorusage = 3: EXIT FUNCTION

    lhs = 7
    IF operator$ = "NOT" THEN info$ = "~": operatorusage = 5: EXIT FUNCTION
    IF operator$ = "_NEGATE" THEN info$ = "!": operatorusage = 6: EXIT FUNCTION

    IF Debug THEN PRINT #9, "INVALID NUMBERIC OPERATOR!": END

END FUNCTION

FUNCTION refer$ (a2$, typ AS LONG, method AS LONG)
    typbak = typ
    'method: 0 return an equation which calculates the value of the "variable"
    '        1 return the C name of the variable, typ will be left unchanged

    DIM udtElem AS LONG
    a$ = a2$

    'retrieve ID
    i = INSTR(a$, sp3)
    IF i THEN
        idnumber = VAL(LEFT$(a$, i - 1)): a$ = RIGHT$(a$, LEN(a$) - i)
    ELSE
        idnumber = VAL(a$)
    END IF
    getid idnumber
    IF Error_Happened THEN EXIT FUNCTION

    'UDT?
    IF typ AND ISUDT THEN
        IF method = 1 THEN
            n$ = "UDT_" + RTRIM$(id.n)
            IF id.t = 0 THEN n$ = "ARRAY_" + n$
            n$ = scope$ + n$
            refer$ = n$
            EXIT FUNCTION
        END IF

        'print "UDTSUBSTRING[idX|u|e|o]:"+a$

        u = VAL(a$)
        i = INSTR(a$, sp3): a$ = RIGHT$(a$, LEN(a$) - i): udtElem = VAL(a$)
        i = INSTR(a$, sp3): o$ = RIGHT$(a$, LEN(a$) - i)
        n$ = "UDT_" + RTRIM$(id.n)
        data_ref$ = scope$ + n$
        IF id.t = 0 THEN
            arr_desc_expr$ = scope$ + "ARRAY_" + n$
            data_ref$ = arr_desc_expr$ + "[0]"
        END IF
        IF udtElem = 0 THEN Give_Error "User defined types in expressions are invalid": EXIT FUNCTION
        IF typ AND ISOFFSETINBITS THEN Give_Error "Cannot resolve bit-length variables inside user defined types": EXIT FUNCTION

        IF id.t = 0 AND CheckingOn THEN
            IF udtearrayelements(udtElem) THEN
                guard_udt = id.arraytype AND UDTMASK
                guard_mode = 0
                IF id.dynudt THEN guard_mode = id.dynudtmode
                data_ref$ = UDTRootDataGuard$(arr_desc_expr$, guard_udt, guard_mode)
                IF Error_Happened THEN EXIT FUNCTION
            END IF
        END IF

        IF typ AND ISSTRING THEN
            IF typ AND ISFIXEDLENGTH THEN
                o2$ = "(((uint8*)" + data_ref$ + ")+(" + o$ + "))"
                r$ = "qbs_new_fixed(" + o2$ + "," + _TOSTR$(udtetypesize(udtElem)) + ",1)"
                typ = STRINGTYPE + ISFIXEDLENGTH 'ISPOINTER retained, it is still a pointer!
            ELSE
                r$ = "*((qbs**)((char*)" + data_ref$ + "+(" + o$ + ")))"
                typ = STRINGTYPE
            END IF
        ELSE
            typ = typ - ISUDT - ISREFERENCE - ISPOINTER
            IF typ AND ISARRAY THEN typ = typ - ISARRAY
            t$ = typ2ctyp$(typ, "")
            IF Error_Happened THEN EXIT FUNCTION
            o2$ = "(((char*)" + data_ref$ + ")+(" + o$ + "))"
            r$ = "*" + "(" + t$ + "*)" + o2$
        END IF

        'print "REFER:"+r$+","+_TOSTR$(typ)
        refer$ = r$
        EXIT FUNCTION
    END IF


    'array?
    IF id.arraytype THEN

        n$ = RTRIM$(id.callname)
        IF method = 1 THEN
            refer$ = n$
            typ = typbak
            EXIT FUNCTION
        END IF
        typ = typ - ISPOINTER - ISREFERENCE 'typ now looks like a regular value

        IF (typ AND ISSTRING) THEN
            IF (typ AND ISFIXEDLENGTH) THEN
                offset$ = "&((uint8*)(" + n$ + "[0]))[(" + a$ + ")*" + _TOSTR$(id.tsize) + "]"
                r$ = "qbs_new_fixed(" + offset$ + "," + _TOSTR$(id.tsize) + ",1)"
            ELSE
                r$ = "((qbs*)(((uint64*)(" + n$ + "[0]))[" + a$ + "]))"
            END IF
            stringprocessinghappened = 1
            refer$ = r$
            EXIT FUNCTION
        END IF

        IF (typ AND ISOFFSETINBITS) THEN
            'IF (typ AND ISUNSIGNED) THEN r$ = "getubits_" ELSE r$ = "getbits_"
            'r$ = r$ + _TOSTR$(typ AND UDTMASK) + "("
            IF (typ AND ISUNSIGNED) THEN r$ = "getubits" ELSE r$ = "getbits"
            r$ = r$ + "(" + _TOSTR$(typ AND UDTMASK) + ","
            r$ = r$ + "(uint8*)(" + n$ + "[0])" + ","
            r$ = r$ + a$ + ")"
            refer$ = r$
            EXIT FUNCTION
        ELSE
            t$ = ""
            IF (typ AND ISFLOAT) THEN
                IF (typ AND UDTMASK) = 32 THEN t$ = "float"
                IF (typ AND UDTMASK) = 64 THEN t$ = "double"
                IF (typ AND UDTMASK) = 256 THEN t$ = "long double"
            ELSE
                IF (typ AND ISUNSIGNED) THEN
                    IF (typ AND UDTMASK) = 8 THEN t$ = "uint8"
                    IF (typ AND UDTMASK) = 16 THEN t$ = "uint16"
                    IF (typ AND UDTMASK) = 32 THEN t$ = "uint32"
                    IF (typ AND UDTMASK) = 64 THEN t$ = "uint64"
                    IF typ AND ISOFFSET THEN t$ = "uptrszint"
                ELSE
                    IF (typ AND UDTMASK) = 8 THEN t$ = "int8"
                    IF (typ AND UDTMASK) = 16 THEN t$ = "int16"
                    IF (typ AND UDTMASK) = 32 THEN t$ = "int32"
                    IF (typ AND UDTMASK) = 64 THEN t$ = "int64"
                    IF typ AND ISOFFSET THEN t$ = "ptrszint"
                END IF
            END IF
        END IF
        IF t$ = "" THEN Give_Error "Cannot find C type to return array data": EXIT FUNCTION
        r$ = "((" + t$ + "*)(" + n$ + "[0]))[" + a$ + "]"
        refer$ = r$
        EXIT FUNCTION
    END IF 'array

    'variable?
    IF id.t THEN
        r$ = RTRIM$(id.n)
        t = id.t
        'remove irrelevant flags
        IF (t AND ISINCONVENTIONALMEMORY) THEN t = t - ISINCONVENTIONALMEMORY
        'string?
        IF (t AND ISSTRING) THEN
            IF (t AND ISFIXEDLENGTH) THEN
                r$ = scope$ + "STRING" + _TOSTR$(id.tsize) + "_" + r$: GOTO ref
            END IF
            r$ = scope$ + "STRING_" + r$: GOTO ref
        END IF
        'bit-length single variable?
        IF (t AND ISOFFSETINBITS) THEN
            IF (t AND ISUNSIGNED) THEN
                r$ = "*" + scope$ + "UBIT" + _TOSTR$(t AND UDTMASK) + "_" + r$
            ELSE
                r$ = "*" + scope$ + "BIT" + _TOSTR$(t AND UDTMASK) + "_" + r$
            END IF
            GOTO ref
        END IF
        IF t = BYTETYPE THEN r$ = "*" + scope$ + "BYTE_" + r$: GOTO ref
        IF t = UBYTETYPE THEN r$ = "*" + scope$ + "UBYTE_" + r$: GOTO ref
        IF t = INTEGERTYPE THEN r$ = "*" + scope$ + "INTEGER_" + r$: GOTO ref
        IF t = UINTEGERTYPE THEN r$ = "*" + scope$ + "UINTEGER_" + r$: GOTO ref
        IF t = LONGTYPE THEN r$ = "*" + scope$ + "LONG_" + r$: GOTO ref
        IF t = ULONGTYPE THEN r$ = "*" + scope$ + "ULONG_" + r$: GOTO ref
        IF t = INTEGER64TYPE THEN r$ = "*" + scope$ + "INTEGER64_" + r$: GOTO ref
        IF t = UINTEGER64TYPE THEN r$ = "*" + scope$ + "UINTEGER64_" + r$: GOTO ref
        IF t = SINGLETYPE THEN r$ = "*" + scope$ + "SINGLE_" + r$: GOTO ref
        IF t = DOUBLETYPE THEN r$ = "*" + scope$ + "DOUBLE_" + r$: GOTO ref
        IF t = FLOATTYPE THEN r$ = "*" + scope$ + "FLOAT_" + r$: GOTO ref
        IF t = OFFSETTYPE THEN r$ = "*" + scope$ + "OFFSET_" + r$: GOTO ref
        IF t = UOFFSETTYPE THEN r$ = "*" + scope$ + "UOFFSET_" + r$: GOTO ref
        ref:
        IF (t AND ISSTRING) THEN stringprocessinghappened = 1
        IF (t AND ISPOINTER) THEN t = t - ISPOINTER
        typ = t
        IF method = 1 THEN
            IF LEFT$(r$, 1) = "*" THEN r$ = RIGHT$(r$, LEN(r$) - 1)
            typ = typbak
        END IF
        refer$ = r$
        EXIT FUNCTION
    END IF 'variable



END FUNCTION

SUB regid
    idn = idn + 1

    IF idn > ids_max THEN
        ids_max = ids_max * 2
        REDIM _PRESERVE ids(1 TO ids_max) AS idstruct
        REDIM _PRESERVE cmemlist(1 TO ids_max + 1) AS INTEGER
        REDIM _PRESERVE sfcmemargs(1 TO ids_max + 1) AS STRING * 100
        REDIM _PRESERVE arrayelementslist(1 TO ids_max + 1) AS INTEGER
    END IF

    n$ = RTRIM$(id.n)

    IF reginternalsubfunc = 0 THEN
        autoIncForceUScore = 1
        IF validname(n$) = 0 THEN Give_Error "Invalid name": EXIT SUB
    END IF

    'register case sensitive name if none given
    IF ASC(id.cn) = 32 THEN
        n$ = RTRIM$(id.n)
        id.n = UCASE$(n$)
        id.cn = n$
    END IF

    id.insubfunc = subfunc
    id.insubfuncn = subfuncn

    'note: cannot be STATIC and SHARED at the same time
    IF dimshared THEN
        id.share = dimshared
    ELSE
        IF dimstatic THEN id.staticscope = 1
    END IF

    ids(idn) = id

    currentid = idn

    'prepare hash flags and check for conflicts
    hashflags = 1

    'sub/function?
    'Note: QBASIC does not allow: Internal type names (INTEGER,LONG,...)
    IF id.subfunc THEN
        ids(currentid).internal_subfunc = reginternalsubfunc
        IF id.subfunc = 1 THEN hashflags = hashflags + HASHFLAG_FUNCTION ELSE hashflags = hashflags + HASHFLAG_SUB
        IF reginternalsubfunc = 0 THEN 'allow internal definition of subs/functions without checks
            hashchkflags = HASHFLAG_RESERVED + HASHFLAG_CONSTANT
            IF id.subfunc = 1 THEN hashchkflags = hashchkflags + HASHFLAG_FUNCTION ELSE hashchkflags = hashchkflags + HASHFLAG_SUB
            hashres = HashFind(n$, hashchkflags, hashresflags, hashresref)
            DO WHILE hashres
                IF hashres THEN
                    'Note: Numeric sub/function names like 'mid' do not clash with Internal string sub/function names
                    '      like 'MID$' because MID$ always requires a '$'. For user defined string sub/function names
                    '      the '$' would be optional so the rule should not be applied there.
                    allow = 0
                    IF hashresflags AND (HASHFLAG_FUNCTION + HASHFLAG_SUB) THEN
                        IF RTRIM$(ids(hashresref).musthave) = "$" THEN
                            IF INSTR(ids(currentid).mayhave, "$") = 0 THEN allow = 1
                        END IF
                    END IF
                    IF allow = 0 THEN Give_Error "Name already in use (" + n$ + ")": EXIT SUB
                END IF 'hashres
                IF hashres <> 1 THEN hashres = HashFindCont(hashresflags, hashresref) ELSE hashres = 0
            LOOP
            IF idemode THEN
                IF INSTR(listOfCustomKeywords$, "@" + UCASE$(n$) + "@") = 0 THEN
                    listOfCustomKeywords$ = listOfCustomKeywords$ + "@" + UCASE$(n$) + "@"
                END IF
            END IF
        END IF 'reginternalsubfunc = 0
    END IF

    'variable?
    IF id.t THEN
        hashflags = hashflags + HASHFLAG_VARIABLE
        IF reginternalvariable = 0 THEN
            allow = 0
            var_recheck:
            IF ASC(id.musthave) = 32 THEN astype2 = 1 '"AS type" declaration?
            scope2 = subfuncn
            hashchkflags = HASHFLAG_RESERVED + HASHFLAG_SUB + HASHFLAG_FUNCTION + HASHFLAG_CONSTANT + HASHFLAG_VARIABLE
            hashres = HashFind(n$, hashchkflags, hashresflags, hashresref)
            DO WHILE hashres

                'conflict with reserved word?
                IF hashresflags AND HASHFLAG_RESERVED THEN
                    musthave$ = RTRIM$(id.musthave)
                    IF INSTR(musthave$, "$") THEN
                        'All reserved words can be used as variables in QBASIC if "$" is appended to the variable name!
                        '(allow)
                    ELSE
                        Give_Error "Name already in use (" + n$ + ")": EXIT SUB 'Conflicts with reserved word
                    END IF
                END IF 'HASHFLAG_RESERVED

                'conflict with sub/function?
                IF hashresflags AND (HASHFLAG_FUNCTION + HASHFLAG_SUB) THEN
                    IF ids(hashresref).internal_subfunc = 0 THEN Give_Error "Name already in use (" + n$ + ")": EXIT SUB 'QBASIC doesn't allow a variable of the same name as a user-defined sub/func
                    IF RTRIM$(id.n) = "WIDTH" AND ids(hashresref).subfunc = 2 THEN GOTO varname_exception
                    musthave$ = RTRIM$(id.musthave)
                    IF LEN(musthave$) = 0 THEN
                        IF RTRIM$(ids(hashresref).musthave) = "$" THEN
                            'a sub/func requiring "$" can co-exist with implicit numeric variables
                            IF INSTR(id.mayhave, "$") THEN Give_Error "Name already in use (" + n$ + ")": EXIT SUB
                        ELSE
                            Give_Error "Name already in use (" + n$ + ")": EXIT SUB 'Implicitly defined variables cannot conflict with sub/func names
                        END IF
                    END IF 'len(musthave$)=0
                    IF INSTR(musthave$, "$") THEN
                        IF RTRIM$(ids(hashresref).musthave) = "$" THEN Give_Error "Name already in use (" + n$ + ")": EXIT SUB 'A sub/function name already exists as a string
                        '(allow)
                    ELSE
                        IF RTRIM$(ids(hashresref).musthave) <> "$" THEN Give_Error "Name already in use (" + n$ + ")": EXIT SUB 'A non-"$" sub/func name already exists with this name
                    END IF
                END IF 'HASHFLAG_FUNCTION + HASHFLAG_SUB

                'conflict with constant?
                IF hashresflags AND HASHFLAG_CONSTANT THEN
                    scope1 = constsubfunc(hashresref)
                    IF (scope1 = 0 AND AllowLocalName = 0) OR scope1 = scope2 THEN Give_Error "Name already in use (" + n$ + ")": EXIT SUB
                END IF

                'conflict with variable?
                IF hashresflags AND HASHFLAG_VARIABLE THEN
                    astype1 = 0: IF ASC(ids(hashresref).musthave) = 32 THEN astype1 = 1
                    scope1 = ids(hashresref).insubfuncn
                    IF astype1 = 1 AND astype2 = 1 THEN
                        IF scope1 = scope2 THEN Give_Error "Name already in use (" + n$ + ")": EXIT SUB
                    END IF
                    'same type?
                    IF id.t = ids(hashresref).t THEN
                        IF id.tsize = ids(hashresref).tsize THEN
                            IF scope1 = scope2 THEN Give_Error "Name already in use (" + n$ + ")": EXIT SUB
                        END IF
                    END IF
                    'will astype'd fixed STRING-variable mask a non-fixed string?
                    IF id.t AND ISFIXEDLENGTH THEN
                        IF astype2 = 1 THEN
                            IF ids(hashresref).t AND ISSTRING THEN
                                IF (ids(hashresref).t AND ISFIXEDLENGTH) = 0 THEN
                                    IF scope1 = scope2 THEN Give_Error "Name already in use (" + n$ + ")": EXIT SUB
                                END IF
                            END IF
                        END IF
                    END IF
                END IF

                varname_exception:
                IF hashres <> 1 THEN hashres = HashFindCont(hashresflags, hashresref) ELSE hashres = 0
            LOOP
        END IF 'reginternalvariable
    END IF 'variable

    'array?
    IF id.arraytype THEN
        hashflags = hashflags + HASHFLAG_ARRAY
        allow = 0
        ary_recheck:
        scope2 = subfuncn
        IF ASC(id.musthave) = 32 THEN astype2 = 1 '"AS type" declaration?
        hashchkflags = HASHFLAG_RESERVED + HASHFLAG_SUB + HASHFLAG_FUNCTION + HASHFLAG_ARRAY
        hashres = HashFind(n$, hashchkflags, hashresflags, hashresref)
        DO WHILE hashres

            'conflict with reserved word?
            IF hashresflags AND HASHFLAG_RESERVED THEN
                musthave$ = RTRIM$(id.musthave)
                IF INSTR(musthave$, "$") THEN
                    'All reserved words can be used as variables in QBASIC if "$" is appended to the variable name!
                    '(allow)
                ELSE
                    Give_Error "Name already in use (" + n$ + ")": EXIT SUB 'Conflicts with reserved word
                END IF
            END IF 'HASHFLAG_RESERVED

            'conflict with sub/function?
            IF hashresflags AND (HASHFLAG_FUNCTION + HASHFLAG_SUB) THEN
                IF ids(hashresref).internal_subfunc = 0 THEN Give_Error "Name already in use (" + n$ + ")": EXIT SUB 'QBASIC doesn't allow a variable of the same name as a user-defined sub/func
                IF RTRIM$(id.n) = "WIDTH" AND ids(hashresref).subfunc = 2 THEN GOTO arrayname_exception
                musthave$ = RTRIM$(id.musthave)

                IF LEN(musthave$) = 0 THEN
                    IF RTRIM$(ids(hashresref).musthave) = "$" THEN
                        'a sub/func requiring "$" can co-exist with implicit numeric variables
                        IF INSTR(id.mayhave, "$") THEN Give_Error "Name already in use (" + n$ + ")": EXIT SUB
                    ELSE
                        Give_Error "Name already in use (" + n$ + ")": EXIT SUB 'Implicitly defined variables cannot conflict with sub/func names
                    END IF
                END IF 'len(musthave$)=0
                IF INSTR(musthave$, "$") THEN
                    IF RTRIM$(ids(hashresref).musthave) = "$" THEN Give_Error "Name already in use (" + n$ + ")": EXIT SUB 'A sub/function name already exists as a string
                    '(allow)
                ELSE
                    IF RTRIM$(ids(hashresref).musthave) <> "$" THEN Give_Error "Name already in use (" + n$ + ")": EXIT SUB 'A non-"$" sub/func name already exists with this name
                END IF
            END IF 'HASHFLAG_FUNCTION + HASHFLAG_SUB

            'conflict with array?
            IF hashresflags AND HASHFLAG_ARRAY THEN
                astype1 = 0: IF ASC(ids(hashresref).musthave) = 32 THEN astype1 = 1
                scope1 = ids(hashresref).insubfuncn
                IF astype1 = 1 AND astype2 = 1 THEN
                    IF scope1 = scope2 THEN Give_Error "Name already in use (" + n$ + ")": EXIT SUB
                END IF
                'same type?
                IF id.arraytype = ids(hashresref).arraytype THEN
                    IF id.tsize = ids(hashresref).tsize THEN
                        IF scope1 = scope2 THEN Give_Error "Name already in use (" + n$ + ")": EXIT SUB
                    END IF
                END IF
                'will astype'd fixed STRING-variable mask a non-fixed string?
                IF id.arraytype AND ISFIXEDLENGTH THEN
                    IF astype2 = 1 THEN
                        IF ids(hashresref).arraytype AND ISSTRING THEN
                            IF (ids(hashresref).arraytype AND ISFIXEDLENGTH) = 0 THEN
                                IF scope1 = scope2 THEN Give_Error "Name already in use (" + n$ + ")": EXIT SUB
                            END IF
                        END IF
                    END IF
                END IF
            END IF

            arrayname_exception:
            IF hashres <> 1 THEN hashres = HashFindCont(hashresflags, hashresref) ELSE hashres = 0
        LOOP
    END IF 'array

    'add it to the hash table
    HashAdd n$, hashflags, currentid

END SUB

SUB copy_preserve_udt_varstrings (dstbase$, srcbase$, u AS LONG, dstoff$, srcoff$, acc$) 'helper for _Preserve for UDT contains strings and strings array
    DIM e AS LONG
    DIM offbytes AS LONG
    DIM memberbytes AS LONG
    DIM elembytes AS LONG
    DIM t AS LONG
    DIM i AS LONG
    DIM dstmember$
    DIM srcmember$
    DIM dstq$
    DIM srcq$
    DIM nextdstoff$
    DIM nextsrcoff$

    offbytes = 0
    e = udtxnext(u)

    DO WHILE e
        memberbytes = udtesize(e) \ 8
        t = udtetype(e)

        IF udtearrayelements(e) THEN
            elembytes = memberbytes \ udtearrayelements(e)

            IF (t AND ISSTRING) <> 0 AND (t AND ISFIXEDLENGTH) = 0 THEN
                FOR i = 0 TO udtearrayelements(e) - 1
                    dstmember$ = "((char*)(" + dstbase$ + ")+((" + dstoff$ + ")+" + _TOSTR$(offbytes + i * elembytes) + "))"
                    srcmember$ = "((char*)(" + srcbase$ + ")+((" + srcoff$ + ")+" + _TOSTR$(offbytes + i * elembytes) + "))"
                    dstq$ = "(*(qbs**)(" + dstmember$ + "))"
                    srcq$ = "(*(qbs**)(" + srcmember$ + "))"
                    acc$ = acc$ + CRLF + "qbs_set(" + dstq$ + "," + srcq$ + ");"
                NEXT
            ELSEIF (t AND ISUDT) <> 0 AND udtxvariable(t AND UDTMASK) THEN
                FOR i = 0 TO udtearrayelements(e) - 1
                    nextdstoff$ = "((" + dstoff$ + ")+" + _TOSTR$(offbytes + i * elembytes) + ")"
                    nextsrcoff$ = "((" + srcoff$ + ")+" + _TOSTR$(offbytes + i * elembytes) + ")"
                    copy_preserve_udt_varstrings dstbase$, srcbase$, t AND UDTMASK, nextdstoff$, nextsrcoff$, acc$
                NEXT
            ELSE
                dstmember$ = "((char*)(" + dstbase$ + ")+((" + dstoff$ + ")+" + _TOSTR$(offbytes) + "))"
                srcmember$ = "((char*)(" + srcbase$ + ")+((" + srcoff$ + ")+" + _TOSTR$(offbytes) + "))"
                acc$ = acc$ + CRLF + "memcpy((void*)(" + dstmember$ + "),(void*)(" + srcmember$ + ")," + _TOSTR$(memberbytes) + ");"
            END IF

        ELSE
            dstmember$ = "((char*)(" + dstbase$ + ")+((" + dstoff$ + ")+" + _TOSTR$(offbytes) + "))"
            srcmember$ = "((char*)(" + srcbase$ + ")+((" + srcoff$ + ")+" + _TOSTR$(offbytes) + "))"

            IF (t AND ISSTRING) <> 0 AND (t AND ISFIXEDLENGTH) = 0 THEN
                dstq$ = "(*(qbs**)(" + dstmember$ + "))"
                srcq$ = "(*(qbs**)(" + srcmember$ + "))"
                acc$ = acc$ + CRLF + "qbs_set(" + dstq$ + "," + srcq$ + ");"
            ELSEIF (t AND ISUDT) <> 0 AND udtxvariable(t AND UDTMASK) THEN
                copy_preserve_udt_varstrings dstbase$, srcbase$, t AND UDTMASK, "((" + dstoff$ + ")+" + _TOSTR$(offbytes) + ")", "((" + srcoff$ + ")+" + _TOSTR$(offbytes) + ")", acc$
            ELSE
                acc$ = acc$ + CRLF + "memcpy((void*)(" + dstmember$ + "),(void*)(" + srcmember$ + ")," + _TOSTR$(memberbytes) + ");"
            END IF
        END IF

        offbytes = offbytes + memberbytes
        e = udtenext(e)
    LOOP
END SUB



'$INCLUDE:'subs_functions\subs_functions.bas'

FUNCTION scope$
    IF id.share THEN scope$ = module$ + "__": EXIT FUNCTION
    scope$ = module$ + "_" + subfunc$ + "_"
END FUNCTION

FUNCTION seperateargs (a$, ca$, pass&)
    pass& = 0

    FOR i = 1 TO OptMax: separgs(i) = "": NEXT
    FOR i = 1 TO OptMax + 1: separgslayout(i) = "": NEXT
    FOR i = 1 TO OptMax
        Lev(i) = 0
        EntryLev(i) = 0
        DitchLev(i) = 0
        DontPass(i) = 0
        TempList(i) = 0
        PassRule(i) = 0
        LevelEntered(i) = 0
    NEXT

    DIM id2 AS idstruct

    id2 = id

    IF id2.args = 0 THEN EXIT FUNCTION 'no arguments!


    s$ = id2.specialformat
    s$ = RTRIM$(s$)

    'build a special format if none exists
    IF s$ = "" THEN
        FOR i = 1 TO id2.args
            IF i <> 1 THEN s$ = s$ + ",?" ELSE s$ = "?"
        NEXT
    END IF

    'note: dim'd arrays moved to global to prevent high recreation cost

    PassFlag = 1
    nextentrylevel = 0
    nextentrylevelset = 1
    level = 0
    lastt = 0
    ditchlevel = 0
    FOR i = 1 TO LEN(s$)
        s2$ = MID$(s$, i, 1)

        IF s2$ = "[" THEN
            level = level + 1
            LevelEntered(level) = 0
            GOTO nextsymbol
        END IF

        IF s2$ = "]" THEN
            level = level - 1
            IF level < ditchlevel THEN ditchlevel = level
            GOTO nextsymbol
        END IF

        IF s2$ = "{" THEN
            lastt = lastt + 1: Lev(lastt) = level: PassRule(lastt) = 0
            DitchLev(lastt) = ditchlevel: ditchlevel = level 'store & reset ditch level
            i = i + 1
            i2 = INSTR(i, s$, "}")
            numopts = 0
            nextopt:
            numopts = numopts + 1
            i3 = INSTR(i + 1, s$, "|")
            IF i3 <> 0 AND i3 < i2 THEN
                Opt(lastt, numopts) = MID$(s$, i, i3 - i)
                i = i3 + 1: GOTO nextopt
            END IF
            Opt(lastt, numopts) = MID$(s$, i, i2 - i)
            T(lastt) = numopts
            'calculate words in each option
            FOR x = 1 TO T(lastt)
                w = 1
                x2 = 1
                newword:
                IF INSTR(x2, RTRIM$(Opt(lastt, x)), " ") THEN w = w + 1: x2 = INSTR(x2, RTRIM$(Opt(lastt, x)), " ") + 1: GOTO newword
                OptWords(lastt, x) = w
            NEXT
            i = i2

            'set entry level routine
            EntryLev(lastt) = level 'default level when continuing a previously entered level
            IF LevelEntered(level) = 0 THEN
                EntryLev(lastt) = 0
                FOR i2 = 1 TO level - 1
                    IF LevelEntered(i2) = 1 THEN EntryLev(lastt) = i2
                NEXT
            END IF
            LevelEntered(level) = 1

            GOTO nextsymbol
        END IF

        IF s2$ = "?" THEN
            lastt = lastt + 1: Lev(lastt) = level: PassRule(lastt) = 0
            DitchLev(lastt) = ditchlevel: ditchlevel = level 'store & reset ditch level
            T(lastt) = 0
            'set entry level routine
            EntryLev(lastt) = level 'default level when continuing a previously entered level
            IF LevelEntered(level) = 0 THEN
                EntryLev(lastt) = 0
                FOR i2 = 1 TO level - 1
                    IF LevelEntered(i2) = 1 THEN EntryLev(lastt) = i2
                NEXT
            END IF
            LevelEntered(level) = 1

            GOTO nextsymbol
        END IF

        'assume "special" character (like ( ) , . - etc.)
        lastt = lastt + 1: Lev(lastt) = level: PassRule(lastt) = 0
        DitchLev(lastt) = ditchlevel: ditchlevel = level 'store & reset ditch level
        T(lastt) = 1: Opt(lastt, 1) = s2$: OptWords(lastt, 1) = 1: DontPass(lastt) = 1

        'set entry level routine
        EntryLev(lastt) = level 'default level when continuing a previously entered level
        IF LevelEntered(level) = 0 THEN
            EntryLev(lastt) = 0
            FOR i2 = 1 TO level - 1
                IF LevelEntered(i2) = 1 THEN EntryLev(lastt) = i2
            NEXT
        END IF
        LevelEntered(level) = 1

        GOTO nextsymbol

        nextsymbol:
    NEXT


    IF Debug THEN
        PRINT #9, "--------SEPARATE ARGUMENTS REPORT #1:1--------"
        FOR i = 1 TO lastt
            PRINT #9, i, "OPT=" + CHR$(34) + RTRIM$(Opt(i, 1)) + CHR$(34)
            PRINT #9, i, "OPTWORDS="; OptWords(i, 1)
            PRINT #9, i, "T="; T(i)
            PRINT #9, i, "DONTPASS="; DontPass(i)
            PRINT #9, i, "PASSRULE="; PassRule(i)
            PRINT #9, i, "LEV="; Lev(i)
            PRINT #9, i, "ENTRYLEV="; EntryLev(i)
        NEXT
    END IF


    'Any symbols already have dontpass() set to 1
    'This sets any {}blocks with only one option/word (eg. {PRINT}) at the lowest level to dontpass()=1
    'because their content is manadatory and there is no choice as to which word to use
    FOR x = 1 TO lastt
        IF Lev(x) = 0 THEN
            IF T(x) = 1 THEN DontPass(x) = 1
        END IF
    NEXT

    IF Debug THEN
        PRINT #9, "--------SEPARATE ARGUMENTS REPORT #1:2--------"
        FOR i = 1 TO lastt
            PRINT #9, i, "OPT=" + CHR$(34) + RTRIM$(Opt(i, 1)) + CHR$(34)
            PRINT #9, i, "OPTWORDS="; OptWords(i, 1)
            PRINT #9, i, "T="; T(i)
            PRINT #9, i, "DONTPASS="; DontPass(i)
            PRINT #9, i, "PASSRULE="; PassRule(i)
            PRINT #9, i, "LEV="; Lev(i)
            PRINT #9, i, "ENTRYLEV="; EntryLev(i)
        NEXT
    END IF




    x1 = 0 'the 'x' position of the beginning element of the current levelled block
    MustPassOpt = 0 'the 'x' position of the FIRST opt () in the block which must be passed
    MustPassOptNeedsFlag = 0 '{}blocks don't need a flag, ? blocks do

    'Note: For something like [{HELLO}x] a choice between passing 'hello' or passing a flag to signify x was specified
    '      has to be made, in such cases, a flag is preferable to wasting a full new int32 on 'hello'

    templistn = 0
    FOR l = 1 TO 32767
        scannextlevel = 0
        FOR x = 1 TO lastt
            IF Lev(x) > l THEN scannextlevel = 1

            IF x1 THEN
                IF EntryLev(x) < l THEN 'end of block reached
                    IF MustPassOpt THEN
                        'If there's an opt () which must be passed that will be identified,
                        'all the 1 option {}blocks can be assumed...
                        IF MustPassOptNeedsFlag THEN
                            'The MustPassOpt requires a flag, so use the same flag for everything
                            FOR x2 = 1 TO templistn
                                PassRule(TempList(x2)) = PassFlag
                            NEXT
                            PassFlag = PassFlag * 2
                        ELSE
                            'The MustPassOpt is a {}block which doesn't need a flag, so everything else needs to
                            'reference it
                            FOR x2 = 1 TO templistn
                                IF TempList(x2) <> MustPassOpt THEN PassRule(TempList(x2)) = -MustPassOpt
                            NEXT
                        END IF
                    ELSE
                        'if not, use a unique flag for everything in this block
                        FOR x2 = 1 TO templistn: PassRule(TempList(x2)) = PassFlag: NEXT
                        IF templistn <> 0 THEN PassFlag = PassFlag * 2
                    END IF
                    x1 = 0
                END IF
            END IF


            IF Lev(x) = l THEN 'on same level
                IF EntryLev(x) < l THEN 'just (re)entered this level (not continuing along it)
                    x1 = x 'set x1 to the starting element of this level
                    MustPassOpt = 0
                    templistn = 0
                END IF
            END IF

            IF x1 THEN
                IF Lev(x) = l THEN 'same level

                    IF T(x) <> 1 THEN
                        'It isn't a symbol or a {}block with only one option therefore this opt () must be passed
                        IF MustPassOpt = 0 THEN
                            MustPassOpt = x 'Only record the first instance (it MAY require a flag)
                            IF T(x) = 0 THEN MustPassOptNeedsFlag = 1 ELSE MustPassOptNeedsFlag = 0
                        ELSE
                            'Update current MustPassOpt to non-flag-based {}block if possible (to save flag usage)
                            '(Consider [{A|B}?], where a flag is not required)
                            IF MustPassOptNeedsFlag = 1 THEN
                                IF T(x) > 1 THEN
                                    MustPassOpt = x: MustPassOptNeedsFlag = 0
                                END IF
                            END IF
                        END IF
                        'add to list
                        templistn = templistn + 1: TempList(templistn) = x
                    END IF

                    IF T(x) = 1 THEN
                        'It is a symbol or a {}block with only one option
                        'a {}block with only one option MAY not need to be passed
                        'depending on if anything else is in this block could make the existence of this opt () assumed
                        'Note: Symbols which are not encapsulated inside a {}block never need to be passed
                        '      Symbols already have dontpass() set to 1
                        IF DontPass(x) = 0 THEN templistn = templistn + 1: TempList(templistn) = x: DontPass(x) = 1
                    END IF

                END IF
            END IF

        NEXT

        'scan last run (mostly just a copy of code from above)
        IF x1 THEN
            IF MustPassOpt THEN
                'If there's an opt () which must be passed that will be identified,
                'all the 1 option {}blocks can be assumed...
                IF MustPassOptNeedsFlag THEN
                    'The MustPassOpt requires a flag, so use the same flag for everything
                    FOR x2 = 1 TO templistn
                        PassRule(TempList(x2)) = PassFlag
                    NEXT
                    PassFlag = PassFlag * 2
                ELSE
                    'The MustPassOpt is a {}block which doesn't need a flag, so everything else needs to
                    'reference it
                    FOR x2 = 1 TO templistn
                        IF TempList(x2) <> MustPassOpt THEN PassRule(TempList(x2)) = -MustPassOpt
                    NEXT
                END IF
            ELSE
                'if not, use a unique flag for everything in this block
                FOR x2 = 1 TO templistn: PassRule(TempList(x2)) = PassFlag: NEXT
                IF templistn <> 0 THEN PassFlag = PassFlag * 2
            END IF
            x1 = 0
        END IF

        IF scannextlevel = 0 THEN EXIT FOR
    NEXT

    IF Debug THEN
        PRINT #9, "--------SEPARATE ARGUMENTS REPORT #1:3--------"
        FOR i = 1 TO lastt
            PRINT #9, i, "OPT=" + CHR$(34) + RTRIM$(Opt(i, 1)) + CHR$(34)
            PRINT #9, i, "OPTWORDS="; OptWords(i, 1)
            PRINT #9, i, "T="; T(i)
            PRINT #9, i, "DONTPASS="; DontPass(i)
            PRINT #9, i, "PASSRULE="; PassRule(i)
            PRINT #9, i, "LEV="; Lev(i)
            PRINT #9, i, "ENTRYLEV="; EntryLev(i)
        NEXT
    END IF



    FOR i = 1 TO lastt: separgs(i) = "n-ll": NEXT




    'Consider: "?,[?]"
    'Notes: The comma is mandatory but the second ? is entirely optional
    'Consider: "[?[{B}?]{A}]?"
    'Notes: As unlikely as the above is, it is still valid, but pivots on the outcome of {A} being present
    'Consider: "[?]{A}"
    'Consider: "[?{A}][?{B}][?{C}]?"
    'Notes: The trick here is to realize {A} has greater priority than {B}, so all lines of enquiry must
    '       be exhausted before considering {B}

    'Use inquiry approach to solve format
    'Each line of inquiry must be exhausted
    'An expression ("?") simply means a branch where you can scan ahead

    Branches = 0
    DIM BranchFormatPos(1 TO 100) AS LONG
    DIM BranchTaken(1 TO 100) AS LONG
    '1=taken (this usually involves moving up a level)
    '0=not taken
    DIM BranchInputPos(1 TO 100) AS LONG
    DIM BranchWithExpression(1 TO 100) AS LONG
    'non-zero=expression expected before next item for format item value represents
    '0=no expression allowed before next item
    DIM BranchLevel(1 TO 100) AS LONG 'Level before this branch was/wasn't taken

    n = numelements(ca$)
    i = 1 'Position within ca$

    level = 0
    Expression = 0
    FOR x = 1 TO lastt

        ContinueScan:

        IF DitchLev(x) < level THEN 'dropping down to a lower level
            'we can only go as low as the 'ditch' will allow us, which will limit our options
            level = DitchLev(x)
        END IF

        IF EntryLev(x) <= level THEN 'possible to enter level

            'But was this optional or were we forced to be on this level?
            IF EntryLev(x) < Lev(x) THEN
                optional = 1
                IF level > EntryLev(x) THEN optional = 0
            ELSE
                'entrylev=lev
                optional = 0
            END IF

            t = T(x)

            IF t = 0 THEN 'A "?" expression
                IF Expression THEN
                    '*********backtrack************
                    'We are tracking an expression which we assumed would be present but was not
                    GOTO Backtrack
                    '******************************
                END IF
                IF optional THEN
                    Branches = Branches + 1
                    BranchFormatPos(Branches) = x
                    BranchTaken(Branches) = 1
                    BranchInputPos(Branches) = i
                    BranchWithExpression(Branches) = 0
                    BranchLevel(Branches) = level
                    level = Lev(x)
                END IF
                Expression = x
            END IF 'A "?" expression

            IF t THEN

                currentlev = level

                'Add new branch if new level will be entered
                IF optional THEN
                    Branches = Branches + 1
                    BranchFormatPos(Branches) = x
                    BranchTaken(Branches) = 1
                    BranchInputPos(Branches) = i
                    BranchWithExpression(Branches) = Expression
                    BranchLevel(Branches) = level
                END IF

                'Scan for Opt () options
                i1 = i: i2 = i
                IF Expression THEN i2 = n
                'Scan a$ for opt () x
                'Note: Finding the closest opt option is necessary
                'Note: This needs to be bracket sensitive
                OutOfRange = 2147483647
                position = OutOfRange
                which = 0
                IF i <= n THEN 'Past end of contect check
                    FOR o = 1 TO t
                        words = OptWords(x, o)
                        b = 0
                        FOR i3 = i1 TO i2
                            IF i3 + words - 1 <= n THEN 'enough elements exist
                                c$ = getelement$(a$, i3)
                                IF b = 0 THEN
                                    'Build comparison string (spacing elements)
                                    FOR w = 2 TO words
                                        c$ = c$ + " " + getelement$(a$, i3 + w - 1)
                                    NEXT w
                                    'Compare
                                    IF c$ = UCASE$(RTRIM$(Opt(x, o))) THEN
                                        'Record Match
                                        IF i3 < position THEN
                                            position = i3
                                            which = o
                                            bvalue = b
                                            EXIT FOR 'Exit the i3 loop
                                        END IF 'position check
                                    END IF 'match
                                END IF

                                IF ASC(c$) = 44 AND b = 0 THEN
                                    EXIT FOR 'Expressions cannot contain a "," in their base level
                                    'Because this wasn't intercepted by the above code it isn't the Opt either
                                END IF
                                IF ASC(c$) = 40 THEN
                                    b = b + 1
                                END IF
                                IF ASC(c$) = 41 THEN
                                    b = b - 1
                                    IF b = -1 THEN EXIT FOR 'Exited current bracketing level, making any following match invalid
                                END IF

                            END IF 'enough elements exist
                        NEXT i3
                    NEXT o
                END IF 'Past end of contect check

                IF position <> OutOfRange THEN 'Found?
                    'Found...
                    level = Lev(x) 'Adjust level
                    IF Expression THEN
                        'Found...Expression...
                        'Has an expression been provided?
                        IF position > i AND bvalue = 0 THEN
                            'Found...Expression...Provided...
                            separgs(Expression) = getelements$(ca$, i, position - 1)
                            Expression = 0
                            i = position
                        ELSE
                            'Found...Expression...Omitted...
                            '*********backtrack************
                            GOTO OptCheckBacktrack
                            '******************************
                        END IF
                    END IF 'Expression
                    i = i + OptWords(x, which)
                    separgslayout(x) = CHR$(LEN(RTRIM$(Opt(x, which)))) + SCase$(MID$(RTRIM$(Opt(x, which)), 1))
                    separgs(x) = CHR$(0) + _TOSTR$(which)
                ELSE
                    'Not Found...
                    '*********backtrack************
                    OptCheckBacktrack:
                    'Was this optional?
                    IF Lev(x) > EntryLev(x) THEN 'Optional Opt ()?
                        'Not Found...Optional...
                        'Simply don't enter the optional higher level and continue as normal
                        BranchTaken(Branches) = 0
                        level = currentlev 'We aren't entering the level after all, so our level should remain at the opt's entrylevel
                    ELSE
                        Backtrack:
                        'Not Found...Mandatory...
                        '1)Erase previous branches where both options have been tried
                        FOR branch = Branches TO 1 STEP -1 'Remove branches until last taken branch is found
                            IF BranchTaken(branch) THEN EXIT FOR
                            Branches = Branches - 1 'Remove branch (it has already been tried with both possible combinations)
                        NEXT
                        IF Branches = 0 THEN 'All options have been exhausted
                            seperateargs_error = 1
                            seperateargs_error_message = "Syntax error"
                            IF LEN(id2.hr_syntax) > 0 THEN seperateargs_error_message = seperateargs_error_message + " - Reference: " + id2.hr_syntax
                            EXIT FUNCTION
                        END IF
                        '2)Toggle taken branch to untaken and revert
                        BranchTaken(Branches) = 0 'toggle branch to untaken
                        Expression = BranchWithExpression(Branches)
                        i = BranchInputPos(Branches)
                        x = BranchFormatPos(Branches)
                        level = BranchLevel(Branches)
                        '3)Erase any content created after revert position
                        IF Expression THEN separgs(Expression) = "n-ll"
                        FOR x2 = x TO lastt
                            separgs(x2) = "n-ll"
                            separgslayout(x2) = ""
                        NEXT
                    END IF 'Optional Opt ()?
                    '******************************

                END IF 'Found?

            END IF 't

        END IF 'possible to enter level

    NEXT x

    'Final expression?
    IF Expression THEN
        IF i <= n THEN
            separgs(Expression) = getelements$(ca$, i, n)

            'can this be an expression?
            'check it passes bracketting and comma rules
            b = 0
            FOR i2 = i TO n
                c$ = getelement$(a$, i2)
                IF ASC(c$) = 44 AND b = 0 THEN
                    GOTO Backtrack
                END IF
                IF ASC(c$) = 40 THEN
                    b = b + 1
                END IF
                IF ASC(c$) = 41 THEN
                    b = b - 1
                    IF b = -1 THEN GOTO Backtrack
                END IF
            NEXT
            IF b <> 0 THEN GOTO Backtrack

            i = n + 1 'So it passes the test below
        ELSE
            GOTO Backtrack
        END IF
    END IF 'Expression

    IF i <> n + 1 THEN GOTO Backtrack 'Trailing content?

    IF Debug THEN
        PRINT #9, "--------SEPARATE ARGUMENTS REPORT #2--------"
        FOR i = 1 TO lastt
            PRINT #9, i, separgs(i)
        NEXT
    END IF

    '   DIM PassRule(1 TO 100) AS LONG
    '   '0 means no pass rule
    '   'negative values refer to an opt () element
    '   'positive values refer to a flag value
    '   PassFlag = 1


    IF PassFlag <> 1 THEN seperateargs = 1 'Return whether a 'passed' flags variable is required
    pass& = 0 'The 'passed' value (shared by argument reference)

    'Note: The separgs() elements will be compacted to the C++ function arguments
    x = 1 'The new index to move compacted content to within separgs()

    FOR i = 1 TO lastt

        IF DontPass(i) = 0 THEN

            IF PassRule(i) > 0 THEN
                IF separgs(i) <> "n-ll" THEN pass& = pass& OR PassRule(i) 'build 'passed' flags
            END IF

            separgs(x) = separgs(i)
            separgslayout(x) = separgslayout(i)

            IF LEN(separgs(x)) THEN
                IF ASC(separgs(x)) = 0 THEN
                    'switch omit layout tag from item to layout info
                    separgs(x) = RIGHT$(separgs(x), LEN(separgs(x)) - 1)
                    separgslayout(x) = separgslayout(x) + CHR$(0)
                END IF
            END IF

            IF separgs(x) = "n-ll" THEN separgs(x) = "N-LL"
            x = x + 1

        ELSE
            'it's gonna be skipped!
            'add layout to the next one to be safe

            'for syntax such as [{HELLO}] which uses a flag instead of being passed
            IF PassRule(i) > 0 THEN
                IF separgs(i) <> "n-ll" THEN pass& = pass& OR PassRule(i) 'build 'passed' flags
            END IF

            separgslayout(i + 1) = separgslayout(i) + separgslayout(i + 1)

        END IF
    NEXT
    separgslayout(x) = separgslayout(i) 'set final layout

    'x = x - 1
    'PRINT "total arguments:"; x
    'PRINT "pass omit (0/1):"; omit
    'PRINT "pass&="; pass&

END FUNCTION

SUB setrefer (a2$, typ2 AS LONG, e2$, method AS LONG)
    DIM udtElem AS LONG
    a$ = a2$: typ = typ2: e$ = e2$
    IF method <> 1 THEN e$ = fixoperationorder$(e$)
    IF Error_Happened THEN EXIT SUB
    tl$ = tlayout$

    'method: 0 evaulatetotyp e$
    '        1 skip evaluation of e$ and use as is
    '*due to the complexity of setting a reference with a value/string
    ' this function handles the problem

    'retrieve ID
    i = INSTR(a$, sp3)
    IF i THEN
        idnumber = VAL(LEFT$(a$, i - 1)): a$ = RIGHT$(a$, LEN(a$) - i)
    ELSE
        idnumber = VAL(a$)
    END IF
    getid idnumber
    IF Error_Happened THEN EXIT SUB

    'UDT?
    IF typ AND ISUDT THEN

        'print "setrefer-ing a UDT!"
        u = VAL(a$)
        i = INSTR(a$, sp3): a$ = RIGHT$(a$, LEN(a$) - i): udtElem = VAL(a$)
        i = INSTR(a$, sp3): o$ = RIGHT$(a$, LEN(a$) - i)
        n$ = "UDT_" + RTRIM$(id.n): IF id.t = 0 THEN n$ = "ARRAY_" + n$ + "[0]"
        lhsdynudt% = id.dynudt
        lhsdynmode% = id.dynudtmode

        IF udtElem <> 0 AND u = 1 THEN 'Setting _MEM type elements is not allowed!
            Give_Error "Cannot set read-only element of _MEM TYPE": EXIT SUB
        END IF

        IF udtElem = 0 THEN
            'use u and u's size

            IF method <> 0 THEN Give_Error "Unexpected internal code reference to UDT": EXIT SUB
            lhsscope$ = scope$
            e$ = evaluate(e$, t2)
            IF Error_Happened THEN EXIT SUB
            IF (t2 AND ISUDT) = 0 THEN Give_Error "Expected = similar user defined type": EXIT SUB

            rhsdynudt% = 0
            rhsdynmode% = 0
            IF (t2 AND ISREFERENCE) = 0 THEN
                IF t2 AND ISPOINTER THEN
                    src$ = "((char*)" + e$ + ")"
                    e2 = 0: u2 = t2 AND UDTMASK
                ELSE
                    src$ = "((char*)&" + e$ + ")"
                    e2 = 0: u2 = t2 AND UDTMASK
                END IF
                GOTO directudt
            END IF

            '****problem****
            idnumber2 = VAL(e$)
            getid idnumber2


            IF Error_Happened THEN EXIT SUB
            rhsdynudt% = id.dynudt
            rhsdynmode% = id.dynudtmode
            n2$ = "UDT_" + RTRIM$(id.n): IF id.t = 0 THEN n2$ = "ARRAY_" + n2$ + "[0]"
            i = INSTR(e$, sp3): e$ = RIGHT$(e$, LEN(e$) - i): u2 = VAL(e$)
            i = INSTR(e$, sp3): e$ = RIGHT$(e$, LEN(e$) - i): e2 = VAL(e$)
            i = INSTR(e$, sp3): o2$ = RIGHT$(e$, LEN(e$) - i)
            'WARNING: u2 may need minor modifications based on e to see if they are the same

            'we have now established we have 2 pointers to similar data types!
            'ASSUME _BYTE TYPE!!!
            src$ = "((char*)" + scope$ + n2$ + ")+(" + o2$ + ")"
            directudt:
            IF u <> u2 OR e2 <> 0 THEN Give_Error "Expected = similar user defined type": EXIT SUB
            dst$ = "((char*)" + lhsscope$ + n$ + ")+(" + o$ + ")"
            IF (UDTDynHasMemberArrays%(u, lhsdynmode%) OR udtxvariable(u)) AND (lhsdynudt% OR rhsdynudt%) THEN
                IF lhsdynudt% = 0 OR rhsdynudt% = 0 THEN Give_Error "Cannot assign these TYPE values because their nested-array storage layouts are incompatible": EXIT SUB
                IF lhsdynmode% <> rhsdynmode% THEN Give_Error "Cannot assign these TYPE values because their nested-array storage layouts are incompatible": EXIT SUB
                copy_full_udt_dyn dst$, src$, MainTxtBuf, 0, u, lhsdynmode%
            ELSE
                copy_full_udt dst$, src$, MainTxtBuf, 0, u
            END IF

            'print "setFULLUDTrefer!"

            tlayout$ = tl$
            EXIT SUB

        END IF 'e=0

        IF typ AND ISOFFSETINBITS THEN Give_Error "Cannot resolve bit-length variables inside user defined types": EXIT SUB
        IF typ AND ISSTRING THEN
            IF typ AND ISFIXEDLENGTH THEN
                o2$ = "(((uint8*)" + scope$ + n$ + ")+(" + o$ + "))"
                r$ = "qbs_new_fixed(" + o2$ + "," + _TOSTR$(udtetypesize(udtElem)) + ",1)"
            ELSE
                r$ = "*((qbs**)((char*)(" + scope$ + n$ + ")+(" + o$ + ")))"
            END IF
            IF method = 0 THEN e$ = evaluatetotyp(e$, STRINGTYPE - ISPOINTER)
            IF Error_Happened THEN EXIT SUB
            WriteBufLine MainTxtBuf, "qbs_set(" + r$ + "," + e$ + ");"
            WriteBufLine MainTxtBuf, cleanupstringprocessingcall$ + "0);"
        ELSE
            typ = typ - ISUDT - ISREFERENCE - ISPOINTER
            IF typ AND ISARRAY THEN typ = typ - ISARRAY
            t$ = typ2ctyp$(typ, "")
            IF Error_Happened THEN EXIT SUB
            o2$ = "(((char*)" + scope$ + n$ + ")+(" + o$ + "))"
            r$ = "*" + "(" + t$ + "*)" + o2$
            IF method = 0 THEN e$ = evaluatetotyp(e$, typ)
            IF Error_Happened THEN EXIT SUB
            WriteBufLine MainTxtBuf, r$ + "=" + e$ + ";"
        END IF

        'print "setUDTrefer:"+r$,e$
        tlayout$ = tl$
        IF LEFT$(r$, 1) = "*" THEN r$ = MID$(r$, 2)
        EXIT SUB
    END IF


    'array?
    IF id.arraytype THEN
        n$ = RTRIM$(id.callname)
        typ = typ - ISPOINTER - ISREFERENCE 'typ now looks like a regular value

        IF (typ AND ISSTRING) THEN
            IF (typ AND ISFIXEDLENGTH) THEN
                offset$ = "&((uint8*)(" + n$ + "[0]))[tmp_long*" + _TOSTR$(id.tsize) + "]"
                r$ = "qbs_new_fixed(" + offset$ + "," + _TOSTR$(id.tsize) + ",1)"
                WriteBufLine MainTxtBuf, "tmp_long=" + a$ + ";"
                IF method = 0 THEN
                    l$ = "if (!is_error_pending()) qbs_set(" + r$ + "," + evaluatetotyp(e$, typ) + ");"
                    IF Error_Happened THEN EXIT SUB
                ELSE
                    l$ = "if (!is_error_pending()) qbs_set(" + r$ + "," + e$ + ");"
                END IF
                WriteBufLine MainTxtBuf, l$
            ELSE
                WriteBufLine MainTxtBuf, "tmp_long=" + a$ + ";"
                IF method = 0 THEN
                    l$ = "if (!is_error_pending()) qbs_set( ((qbs*)(((uint64*)(" + n$ + "[0]))[tmp_long]))," + evaluatetotyp(e$, typ) + ");"
                    IF Error_Happened THEN EXIT SUB
                ELSE
                    l$ = "if (!is_error_pending()) qbs_set( ((qbs*)(((uint64*)(" + n$ + "[0]))[tmp_long]))," + e$ + ");"
                END IF
                WriteBufLine MainTxtBuf, l$
            END IF
            WriteBufLine MainTxtBuf, cleanupstringprocessingcall$ + "0);"
            tlayout$ = tl$
            IF LEFT$(r$, 1) = "*" THEN r$ = MID$(r$, 2)
            EXIT SUB
        END IF

        IF (typ AND ISOFFSETINBITS) THEN
            'r$ = "setbits_" + _TOSTR$(typ AND UDTMASK) + "("
            r$ = "setbits(" + _TOSTR$(typ AND UDTMASK) + ","
            r$ = r$ + "(uint8*)(" + n$ + "[0])" + ",tmp_long,"
            WriteBufLine MainTxtBuf, "tmp_long=" + a$ + ";"
            IF method = 0 THEN
                l$ = "if (!is_error_pending()) " + r$ + evaluatetotyp(e$, typ) + ");"
                IF Error_Happened THEN EXIT SUB
            ELSE
                l$ = "if (!is_error_pending()) " + r$ + e$ + ");"
            END IF
            WriteBufLine MainTxtBuf, l$
            tlayout$ = tl$
            EXIT SUB
        ELSE
            t$ = ""
            IF (typ AND ISFLOAT) THEN
                IF (typ AND UDTMASK) = 32 THEN t$ = "float"
                IF (typ AND UDTMASK) = 64 THEN t$ = "double"
                IF (typ AND UDTMASK) = 256 THEN t$ = "long double"
            ELSE
                IF (typ AND ISUNSIGNED) THEN
                    IF (typ AND UDTMASK) = 8 THEN t$ = "uint8"
                    IF (typ AND UDTMASK) = 16 THEN t$ = "uint16"
                    IF (typ AND UDTMASK) = 32 THEN t$ = "uint32"
                    IF (typ AND UDTMASK) = 64 THEN t$ = "uint64"
                    IF typ AND ISOFFSET THEN t$ = "uptrszint"
                ELSE
                    IF (typ AND UDTMASK) = 8 THEN t$ = "int8"
                    IF (typ AND UDTMASK) = 16 THEN t$ = "int16"
                    IF (typ AND UDTMASK) = 32 THEN t$ = "int32"
                    IF (typ AND UDTMASK) = 64 THEN t$ = "int64"
                    IF typ AND ISOFFSET THEN t$ = "ptrszint"
                END IF
            END IF
        END IF
        IF t$ = "" THEN Give_Error "Cannot find C type to return array data": EXIT SUB
        WriteBufLine MainTxtBuf, "tmp_long=" + a$ + ";"
        IF method = 0 THEN
            l$ = "if (!is_error_pending()) ((" + t$ + "*)(" + n$ + "[0]))[tmp_long]=" + evaluatetotyp(e$, typ) + ";"
            IF Error_Happened THEN EXIT SUB
        ELSE
            l$ = "if (!is_error_pending()) ((" + t$ + "*)(" + n$ + "[0]))[tmp_long]=" + e$ + ";"
        END IF

        WriteBufLine MainTxtBuf, l$
        tlayout$ = tl$
        EXIT SUB
    END IF 'array

    'variable?
    IF id.t THEN
        r$ = RTRIM$(id.n)
        t = id.t
        'remove irrelevant flags
        IF (t AND ISINCONVENTIONALMEMORY) THEN t = t - ISINCONVENTIONALMEMORY
        typ = t

        'string variable?
        IF (t AND ISSTRING) THEN
            IF (t AND ISFIXEDLENGTH) THEN
                r$ = scope$ + "STRING" + _TOSTR$(id.tsize) + "_" + r$
            ELSE
                r$ = scope$ + "STRING_" + r$
            END IF
            IF method = 0 THEN e$ = evaluatetotyp(e$, ISSTRING)
            IF Error_Happened THEN EXIT SUB
            WriteBufLine MainTxtBuf, "qbs_set(" + r$ + "," + e$ + ");"
            WriteBufLine MainTxtBuf, cleanupstringprocessingcall$ + "0);"
            IF arrayprocessinghappened THEN arrayprocessinghappened = 0
            tlayout$ = tl$
            IF LEFT$(r$, 1) = "*" THEN r$ = MID$(r$, 2)
            EXIT SUB
        END IF

        'bit-length variable?
        IF (t AND ISOFFSETINBITS) THEN
            b = t AND UDTMASK
            IF (t AND ISUNSIGNED) THEN
                r$ = "*" + scope$ + "UBIT" + _TOSTR$(t AND UDTMASK) + "_" + r$
                IF method = 0 THEN e$ = evaluatetotyp(e$, 64& + ISUNSIGNED)
                IF Error_Happened THEN EXIT SUB
                l$ = r$ + "=(" + e$ + ")&" + _TOSTR$(bitmask(b)) + ";"
                WriteBufLine MainTxtBuf, l$
            ELSE
                r$ = "*" + scope$ + "BIT" + _TOSTR$(t AND UDTMASK) + "_" + r$
                IF method = 0 THEN e$ = evaluatetotyp(e$, 64&)
                IF Error_Happened THEN EXIT SUB
                l$ = "if ((" + r$ + "=" + e$ + ")&" + _TOSTR$(2 ^ (b - 1)) + "){"
                WriteBufLine MainTxtBuf, l$
                'signed bit is set
                l$ = r$ + "|=" + _TOSTR$(bitmaskinv(b)) + ";"
                WriteBufLine MainTxtBuf, l$
                WriteBufLine MainTxtBuf, "}else{"
                'signed bit is not set
                l$ = r$ + "&=" + _TOSTR$(bitmask(b)) + ";"
                WriteBufLine MainTxtBuf, l$
                WriteBufLine MainTxtBuf, "}"
            END IF
            IF stringprocessinghappened THEN WriteBufLine MainTxtBuf, cleanupstringprocessingcall$ + "0);": stringprocessinghappened = 0
            IF arrayprocessinghappened THEN arrayprocessinghappened = 0
            tlayout$ = tl$
            IF LEFT$(r$, 1) = "*" THEN r$ = MID$(r$, 2)
            EXIT SUB
        END IF

        'standard variable?
        IF t = BYTETYPE THEN r$ = "*" + scope$ + "BYTE_" + r$: GOTO sref
        IF t = UBYTETYPE THEN r$ = "*" + scope$ + "UBYTE_" + r$: GOTO sref
        IF t = INTEGERTYPE THEN r$ = "*" + scope$ + "INTEGER_" + r$: GOTO sref
        IF t = UINTEGERTYPE THEN r$ = "*" + scope$ + "UINTEGER_" + r$: GOTO sref
        IF t = LONGTYPE THEN r$ = "*" + scope$ + "LONG_" + r$: GOTO sref
        IF t = ULONGTYPE THEN r$ = "*" + scope$ + "ULONG_" + r$: GOTO sref
        IF t = INTEGER64TYPE THEN r$ = "*" + scope$ + "INTEGER64_" + r$: GOTO sref
        IF t = UINTEGER64TYPE THEN r$ = "*" + scope$ + "UINTEGER64_" + r$: GOTO sref
        IF t = SINGLETYPE THEN r$ = "*" + scope$ + "SINGLE_" + r$: GOTO sref
        IF t = DOUBLETYPE THEN r$ = "*" + scope$ + "DOUBLE_" + r$: GOTO sref
        IF t = FLOATTYPE THEN r$ = "*" + scope$ + "FLOAT_" + r$: GOTO sref
        IF t = OFFSETTYPE THEN r$ = "*" + scope$ + "OFFSET_" + r$: GOTO sref
        IF t = UOFFSETTYPE THEN r$ = "*" + scope$ + "UOFFSET_" + r$: GOTO sref
        sref:
        t2 = t - ISPOINTER
        IF method = 0 THEN e$ = evaluatetotyp(e$, t2)
        IF Error_Happened THEN EXIT SUB
        l$ = r$ + "=" + e$ + ";"
        WriteBufLine MainTxtBuf, l$
        IF stringprocessinghappened THEN WriteBufLine MainTxtBuf, cleanupstringprocessingcall$ + "0);": stringprocessinghappened = 0
        IF arrayprocessinghappened THEN arrayprocessinghappened = 0
        tlayout$ = tl$

        IF LEFT$(r$, 1) = "*" THEN r$ = MID$(r$, 2)
        EXIT SUB
    END IF 'variable

    tlayout$ = tl$
END SUB

FUNCTION uniquenumber&
    uniquenumbern = uniquenumbern + 1
    uniquenumber& = uniquenumbern
END FUNCTION

FUNCTION validlabel (LABEL2$)
    create = CreatingLabel: CreatingLabel = 0
    validlabel = 0
    IF LEN(LABEL2$) = 0 THEN EXIT FUNCTION
    clabel$ = LABEL2$
    label$ = UCASE$(LABEL2$)

    n = numelements(label$)

    IF n = 1 THEN

        'Note: Reserved words and internal sub/function names are invalid
        hashres = HashFind(label$, HASHFLAG_RESERVED + HASHFLAG_SUB + HASHFLAG_FUNCTION, hashresflags, hashresref)
        DO WHILE hashres
            IF hashresflags AND (HASHFLAG_SUB + HASHFLAG_FUNCTION) THEN
                IF ids(hashresref).internal_subfunc THEN EXIT FUNCTION

                IF hashresflags AND HASHFLAG_SUB THEN 'could be a label or a sub call!

                    'analyze format
                    IF ASC(ids(hashresref).specialformat) = 32 THEN
                        IF ids(hashresref).args = 0 THEN onecommandsub = 1 ELSE onecommandsub = 0
                    ELSE
                        IF ASC(ids(hashresref).specialformat) <> 91 THEN '"["
                            onecommandsub = 0
                        ELSE
                            onecommandsub = 1
                            a$ = RTRIM$(ids(hashresref).specialformat)
                            b = 1
                            FOR x = 2 TO LEN(a$)
                                a = ASC(a$, x)
                                IF a = 91 THEN b = b + 1
                                IF a = 93 THEN b = b - 1
                                IF b = 0 AND x <> LEN(a$) THEN onecommandsub = 0: EXIT FOR
                            NEXT
                        END IF
                    END IF
                    IF create <> 0 AND onecommandsub = 1 THEN
                        IF INSTR(SubNameLabels$, sp + UCASE$(label$) + sp) = 0 THEN PossibleSubNameLabels$ = PossibleSubNameLabels$ + UCASE$(label$) + sp: EXIT FUNCTION 'treat as sub call
                    END IF

                END IF 'sub name

            ELSE
                'reserved
                EXIT FUNCTION
            END IF
            IF hashres <> 1 THEN hashres = HashFindCont(hashresflags, hashresref) ELSE hashres = 0
        LOOP

        'Numeric label?
        'quasi numbers are possible, but:
        'a) They may only have one decimal place
        'b) They must be typed with the exact same characters to match
        t$ = label$
        'numeric?
        a = ASC(t$)
        IF (a >= 48 AND a <= 57) OR a = 46 THEN

            'refer to original formatting if possible (eg. 1.10 not 1.1)
            x = INSTR(t$, CHR$(44))
            IF x THEN
                t$ = RIGHT$(t$, LEN(t$) - x)
            END IF

            'note: The symbols ! and # are valid trailing symbols in QBASIC, regardless of the number's size,
            '      so they are allowed in QB64 for compatibility reasons
            addsymbol$ = removesymbol$(t$)
            IF Error_Happened THEN EXIT FUNCTION
            IF LEN(addsymbol$) THEN
                IF INSTR(addsymbol$, "$") THEN EXIT FUNCTION
                IF addsymbol$ <> "#" AND addsymbol$ <> "!" THEN addsymbol$ = ""
            END IF

            IF a = 46 THEN dp = 1
            FOR x = 2 TO LEN(t$)
                a = ASC(MID$(t$, x, 1))
                IF a = 46 THEN dp = dp + 1
                IF (a < 48 OR a > 57) AND a <> 46 THEN EXIT FUNCTION 'not numeric
            NEXT x
            IF dp > 1 THEN EXIT FUNCTION 'too many decimal points
            IF dp = 1 AND LEN(t$) = 1 THEN EXIT FUNCTION 'cant have '.' as a label

            tlayout$ = t$ + addsymbol$

            i = INSTR(t$, "."): IF i THEN MID$(t$, i, 1) = "p"
            IF addsymbol$ = "#" THEN t$ = t$ + "d"
            IF addsymbol$ = "!" THEN t$ = t$ + "s"

            IF LEN(t$) > 40 THEN EXIT FUNCTION

            LABEL2$ = t$
            validlabel = 1
            EXIT FUNCTION
        END IF 'numeric

    END IF 'n=1

    'Alpha-numeric label?
    'Build label

    'structure check (???.???.???.???)
    IF (n AND 1) = 0 THEN EXIT FUNCTION 'must be an odd number of elements
    FOR nx = 2 TO n - 1 STEP 2
        a$ = getelement$(LABEL2$, nx)
        IF a$ <> "." THEN EXIT FUNCTION 'every 2nd element must be a period
    NEXT

    'cannot begin with numeric
    c = ASC(clabel$): IF c >= 48 AND c <= 57 THEN EXIT FUNCTION

    'elements check
    label3$ = ""
    FOR nx = 1 TO n STEP 2
        label$ = getelement$(clabel$, nx)

        'alpha-numeric?
        FOR x = 1 TO LEN(label$)
            IF alphanumeric(ASC(label$, x)) = 0 THEN EXIT FUNCTION
        NEXT

        'build label
        IF label3$ = "" THEN label3$ = UCASE$(label$): tlayout$ = label$ ELSE label3$ = label3$ + fix046$ + UCASE$(label$): tlayout$ = tlayout$ + "." + label$
    NEXT nx

    validlabel = 1
    LABEL2$ = label3$

END FUNCTION

SUB xend
    IF GetRCStateVar(vWatchOn) THEN
        WriteBufLine MainTxtBuf, "*__LONG_VWATCH_LINENUMBER= 0; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars);"
    END IF
    WriteBufLine MainTxtBuf, "sub_end();"
END SUB

SUB xfileprint (a$, ca$, n)
    u$ = _TOSTR$(uniquenumber)
    WriteBufLine MainTxtBuf, "tab_spc_cr_size=2;"
    IF n = 2 THEN Give_Error "Expected # ... , ...": EXIT SUB
    a3$ = ""
    b = 0
    FOR i = 3 TO n
        a2$ = getelement$(ca$, i)
        IF a2$ = "(" THEN b = b + 1
        IF a2$ = ")" THEN b = b - 1
        IF a2$ = "," AND b = 0 THEN
            IF a3$ = "" THEN Give_Error "Expected # ... , ...": EXIT SUB
            GOTO printgotfn
        END IF
        IF a3$ = "" THEN a3$ = a2$ ELSE a3$ = a3$ + sp + a2$
    NEXT
    Give_Error "Expected # ... ,": EXIT SUB
    printgotfn:
    e$ = fixoperationorder$(a3$)
    IF Error_Happened THEN EXIT SUB
    l$ = SCase$("Print") + sp + "#" + sp2 + tlayout$ + sp2 + ","
    e$ = evaluatetotyp(e$, 64&)
    IF Error_Happened THEN EXIT SUB
    WriteBufLine MainTxtBuf, "tab_fileno=tmp_fileno=" + e$ + ";"
    WriteBufLine MainTxtBuf, "if (is_error_pending()) goto skip" + u$ + ";"
    i = i + 1

    'PRINT USING? (file)
    IF n >= i THEN
        IF getelement(a$, i) = "USING" THEN
            'get format string
            fpujump:
            l$ = l$ + sp + SCase$("Using")
            e$ = "": b = 0: puformat$ = ""
            FOR i = i + 1 TO n
                a2$ = getelement(ca$, i)
                IF a2$ = "(" THEN b = b + 1
                IF a2$ = ")" THEN b = b - 1
                IF b = 0 THEN
                    IF a2$ = "," THEN Give_Error "Expected PRINT USING #filenumber, formatstring ; ...": EXIT SUB
                    IF a2$ = ";" THEN
                        e$ = fixoperationorder$(e$)
                        IF Error_Happened THEN EXIT SUB
                        l$ = l$ + sp + tlayout$ + sp2 + ";"
                        e$ = evaluate(e$, typ)
                        IF Error_Happened THEN EXIT SUB
                        IF (typ AND ISREFERENCE) THEN e$ = refer(e$, typ, 0)
                        IF Error_Happened THEN EXIT SUB
                        IF (typ AND ISSTRING) = 0 THEN Give_Error "Expected PRINT USING #filenumber, formatstring ; ...": EXIT SUB
                        puformat$ = e$
                        EXIT FOR
                    END IF ';
                END IF 'b
                IF LEN(e$) THEN e$ = e$ + sp + a2$ ELSE e$ = a2$
            NEXT
            IF puformat$ = "" THEN Give_Error "Expected PRINT USING #filenumber, formatstring ; ...": EXIT SUB
            IF i = n THEN Give_Error "Expected PRINT USING #filenumber, formatstring ; ...": EXIT SUB
            'create build string
            WriteBufLine MainTxtBuf, "tqbs=qbs_new(0,0);"
            'set format start/index variable
            WriteBufLine MainTxtBuf, "tmp_long=0;" 'scan format from beginning
            'create string to hold format in for multiple references
            puf$ = "print_using_format" + u$
            IF subfunc = "" THEN
                WriteBufLine DataTxtBuf, "static qbs *" + puf$ + ";"
            ELSE
                WriteBufLine DataTxtBuf, "qbs *" + puf$ + ";"
            END IF
            WriteBufLine MainTxtBuf, puf$ + "=qbs_new(0,0); qbs_set(" + puf$ + "," + puformat$ + ");"
            WriteBufLine MainTxtBuf, "if (is_error_pending()) goto skip" + u$ + ";"
            'print expressions
            b = 0
            e$ = ""
            last = 0
            FOR i = i + 1 TO n
                a2$ = getelement(ca$, i)
                IF a2$ = "(" THEN b = b + 1
                IF a2$ = ")" THEN b = b - 1
                IF b = 0 THEN
                    IF a2$ = ";" OR a2$ = "," THEN
                        fprintulast:
                        e$ = fixoperationorder$(e$)
                        IF Error_Happened THEN EXIT SUB
                        IF last THEN l$ = l$ + sp + tlayout$ ELSE l$ = l$ + sp + tlayout$ + sp2 + a2$
                        e$ = evaluate(e$, typ)
                        IF Error_Happened THEN EXIT SUB
                        IF (typ AND ISREFERENCE) THEN e$ = refer(e$, typ, 0)
                        IF Error_Happened THEN EXIT SUB
                        IF typ AND ISSTRING THEN

                            IF LEFT$(e$, 9) = "func_tab(" OR LEFT$(e$, 9) = "func_spc(" THEN

                                'TAB/SPC exception
                                'note: position in format-string must be maintained
                                '-print any string up until now
                                WriteBufLine MainTxtBuf, "sub_file_print(tmp_fileno,tqbs,0,0,0);"
                                '-print e$
                                WriteBufLine MainTxtBuf, "qbs_set(tqbs," + e$ + ");"
                                WriteBufLine MainTxtBuf, "if (is_error_pending()) goto skip_pu" + u$ + ";"
                                WriteBufLine MainTxtBuf, "sub_file_print(tmp_fileno,tqbs,0,0,0);"
                                '-set length of tqbs to 0
                                WriteBufLine MainTxtBuf, "tqbs->len=0;"

                            ELSE

                                'regular string
                                WriteBufLine MainTxtBuf, "tmp_long=print_using(" + puf$ + ",tmp_long,tqbs," + e$ + ");"

                            END IF

                        ELSE 'not a string
                            IF typ AND ISFLOAT THEN
                                IF (typ AND UDTMASK) = 32 THEN WriteBufLine MainTxtBuf, "tmp_long=print_using_single(" + puf$ + "," + e$ + ",tmp_long,tqbs);"
                                IF (typ AND UDTMASK) = 64 THEN WriteBufLine MainTxtBuf, "tmp_long=print_using_double(" + puf$ + "," + e$ + ",tmp_long,tqbs);"
                                IF (typ AND UDTMASK) > 64 THEN WriteBufLine MainTxtBuf, "tmp_long=print_using_float(" + puf$ + "," + e$ + ",tmp_long,tqbs);"
                            ELSE
                                IF ((typ AND UDTMASK) = 64) AND (typ AND ISUNSIGNED) <> 0 THEN
                                    WriteBufLine MainTxtBuf, "tmp_long=print_using_uinteger64(" + puf$ + "," + e$ + ",tmp_long,tqbs);"
                                ELSE
                                    WriteBufLine MainTxtBuf, "tmp_long=print_using_integer64(" + puf$ + "," + e$ + ",tmp_long,tqbs);"
                                END IF
                            END IF
                        END IF 'string/not string
                        WriteBufLine MainTxtBuf, "if (is_error_pending()) goto skip_pu" + u$ + ";"
                        e$ = ""
                        IF last THEN EXIT FOR
                        GOTO fprintunext
                    END IF
                END IF
                IF LEN(e$) THEN e$ = e$ + sp + a2$ ELSE e$ = a2$
                fprintunext:
            NEXT
            IF e$ <> "" THEN a2$ = "": last = 1: GOTO fprintulast
            WriteBufLine MainTxtBuf, "skip_pu" + u$ + ":"
            'check for errors
            WriteBufLine MainTxtBuf, "if (is_error_pending()){"
            WriteBufLine MainTxtBuf, "g_tmp_long=new_error; new_error=0; sub_file_print(tmp_fileno,tqbs,0,0,0); new_error=g_tmp_long;"
            WriteBufLine MainTxtBuf, "}else{"
            IF a2$ = "," OR a2$ = ";" THEN nl = 0 ELSE nl = 1 'note: a2$ is set to the last element of a$
            WriteBufLine MainTxtBuf, "sub_file_print(tmp_fileno,tqbs,0,0," + _TOSTR$(nl) + ");"
            WriteBufLine MainTxtBuf, "}"
            WriteBufLine MainTxtBuf, "qbs_free(tqbs);"
            WriteBufLine MainTxtBuf, "qbs_free(" + puf$ + ");"
            WriteBufLine MainTxtBuf, "skip" + u$ + ":"
            WriteBufLine MainTxtBuf, cleanupstringprocessingcall$ + "0);"
            WriteBufLine MainTxtBuf, "tab_spc_cr_size=1;"
            tlayout$ = l$
            EXIT SUB
        END IF
    END IF
    'end of print using code

    IF i > n THEN
        WriteBufLine MainTxtBuf, "sub_file_print(tmp_fileno,nothingstring,0,0,1);"
        GOTO printblankline
    END IF
    b = 0
    e$ = ""
    last = 0
    FOR i = i TO n
        a2$ = getelement(ca$, i)
        IF a2$ = "(" THEN b = b + 1
        IF a2$ = ")" THEN b = b - 1
        IF b = 0 THEN
            IF a2$ = ";" OR a2$ = "," OR UCASE$(a2$) = "USING" THEN
                printfilelast:

                IF UCASE$(a2$) = "USING" THEN
                    IF e$ <> "" THEN gotofpu = 1 ELSE GOTO fpujump
                END IF

                IF a2$ = "," THEN usetab = 1 ELSE usetab = 0
                IF last = 1 THEN newline = 1 ELSE newline = 0
                extraspace = 0

                IF LEN(e$) THEN
                    ebak$ = e$
                    pnrtnum = 0
                    printfilenumber:
                    e$ = fixoperationorder$(e$)
                    IF Error_Happened THEN EXIT SUB
                    IF pnrtnum = 0 THEN
                        IF last THEN
                            l$ = l$ + sp + tlayout$
                        ELSEIF gotofpu THEN
                            l$ = l$ + sp + tlayout$
                        ELSE
                            l$ = l$ + sp + tlayout$ + sp2 + a2$
                        END IF
                    END IF
                    e$ = evaluate(e$, typ)
                    IF Error_Happened THEN EXIT SUB
                    IF (typ AND ISSTRING) = 0 THEN
                        e$ = "STR$" + sp + "(" + sp + ebak$ + sp + ")"
                        extraspace = 1
                        pnrtnum = 1
                        GOTO printfilenumber 'force re-evaluation
                    END IF
                    IF (typ AND ISREFERENCE) THEN e$ = refer(e$, typ, 0)
                    IF Error_Happened THEN EXIT SUB
                    'format: string, (1/0) extraspace, (1/0) tab, (1/0)begin a new line
                    WriteBufLine MainTxtBuf, "sub_file_print(tmp_fileno," + e$ + "," + STR$(extraspace) + "," + STR$(usetab) + "," + STR$(newline) + ");"
                ELSE 'len(e$)=0
                    IF a2$ = "," THEN l$ = l$ + sp + a2$
                    IF a2$ = ";" THEN
                        IF RIGHT$(l$, 1) <> ";" THEN l$ = l$ + sp + a2$ 'concat ;; to ;
                    END IF
                    IF usetab THEN WriteBufLine MainTxtBuf, "sub_file_print(tmp_fileno,nothingstring,0,1,0);"
                END IF 'len(e$)
                WriteBufLine MainTxtBuf, "if (is_error_pending()) goto skip" + u$ + ";"

                e$ = ""
                IF gotofpu THEN GOTO fpujump
                IF last THEN EXIT FOR
                GOTO printfilenext
            END IF ', or ;
        END IF 'b=0
        IF e$ <> "" THEN e$ = e$ + sp + a2$ ELSE e$ = a2$
        printfilenext:
    NEXT
    IF e$ <> "" THEN a2$ = "": last = 1: GOTO printfilelast
    printblankline:
    WriteBufLine MainTxtBuf, "skip" + u$ + ":"
    WriteBufLine MainTxtBuf, cleanupstringprocessingcall$ + "0);"
    WriteBufLine MainTxtBuf, "tab_spc_cr_size=1;"
    tlayout$ = l$
END SUB

SUB xfilewrite (ca$, n)
    l$ = SCase$("Write") + sp + "#"
    u$ = _TOSTR$(uniquenumber)
    WriteBufLine MainTxtBuf, "tab_spc_cr_size=2;"
    IF n = 2 THEN Give_Error "Expected # ...": EXIT SUB
    a3$ = ""
    b = 0
    FOR i = 3 TO n
        a2$ = getelement$(ca$, i)
        IF a2$ = "(" THEN b = b + 1
        IF a2$ = ")" THEN b = b - 1
        IF a2$ = "," AND b = 0 THEN
            IF a3$ = "" THEN Give_Error "Expected # ... , ...": EXIT SUB
            GOTO writegotfn
        END IF
        IF a3$ = "" THEN a3$ = a2$ ELSE a3$ = a3$ + sp + a2$
    NEXT
    Give_Error "Expected # ... ,": EXIT SUB
    writegotfn:
    e$ = fixoperationorder$(a3$)
    IF Error_Happened THEN EXIT SUB
    l$ = l$ + sp2 + tlayout$ + sp2 + ","
    e$ = evaluatetotyp(e$, 64&)
    IF Error_Happened THEN EXIT SUB
    WriteBufLine MainTxtBuf, "tab_fileno=tmp_fileno=" + e$ + ";"
    WriteBufLine MainTxtBuf, "if (is_error_pending()) goto skip" + u$ + ";"
    i = i + 1
    IF i > n THEN
        WriteBufLine MainTxtBuf, "sub_file_print(tmp_fileno,nothingstring,0,0,1);"
        GOTO writeblankline
    END IF
    b = 0
    e$ = ""
    last = 0
    FOR i = i TO n
        a2$ = getelement(ca$, i)
        IF a2$ = "(" THEN b = b + 1
        IF a2$ = ")" THEN b = b - 1
        IF b = 0 THEN
            IF a2$ = "," THEN
                writefilelast:
                IF last = 1 THEN newline = 1 ELSE newline = 0
                ebak$ = e$
                reevaled = 0
                writefilenumber:
                e$ = fixoperationorder$(e$)
                IF Error_Happened THEN EXIT SUB
                IF reevaled = 0 THEN
                    l$ = l$ + sp + tlayout$
                    IF last = 0 THEN l$ = l$ + sp2 + ","
                END IF
                e$ = evaluate(e$, typ)
                IF Error_Happened THEN EXIT SUB
                IF reevaled = 0 THEN
                    IF (typ AND ISSTRING) = 0 THEN
                        e$ = "LTRIM$" + sp + "(" + sp + "STR$" + sp + "(" + sp + ebak$ + sp + ")" + sp + ")"
                        IF last = 0 THEN e$ = e$ + sp + "+" + sp + CHR$(34) + "," + CHR$(34) + ",1"
                        reevaled = 1
                        GOTO writefilenumber 'force re-evaluation
                    ELSE
                        e$ = CHR$(34) + "\042" + CHR$(34) + ",1" + sp + "+" + sp + ebak$ + sp + "+" + sp + CHR$(34) + "\042" + CHR$(34) + ",1"
                        IF last = 0 THEN e$ = e$ + sp + "+" + sp + CHR$(34) + "," + CHR$(34) + ",1"
                        reevaled = 1
                        GOTO writefilenumber 'force re-evaluation
                    END IF
                END IF
                IF (typ AND ISREFERENCE) THEN e$ = refer(e$, typ, 0)
                IF Error_Happened THEN EXIT SUB
                'format: string, (1/0) extraspace, (1/0) tab, (1/0)begin a new line
                WriteBufLine MainTxtBuf, "sub_file_print(tmp_fileno," + e$ + ",0,0," + STR$(newline) + ");"
                WriteBufLine MainTxtBuf, "if (is_error_pending()) goto skip" + u$ + ";"
                e$ = ""
                IF last THEN EXIT FOR
                GOTO writefilenext
            END IF ',
        END IF 'b=0
        IF e$ <> "" THEN e$ = e$ + sp + a2$ ELSE e$ = a2$
        writefilenext:
    NEXT
    IF e$ <> "" THEN a2$ = ",": last = 1: GOTO writefilelast
    writeblankline:
    'WriteBufLine MainTxtBuf, "}"'new_error
    WriteBufLine MainTxtBuf, "skip" + u$ + ":"
    WriteBufLine MainTxtBuf, cleanupstringprocessingcall$ + "0);"
    WriteBufLine MainTxtBuf, "tab_spc_cr_size=1;"
    layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
END SUB

SUB xgosub (ca$)
    a2$ = getelement(ca$, 2)
    IF validlabel(a2$) = 0 THEN Give_Error "Invalid label": EXIT SUB

    v = HashFind(a2$, HASHFLAG_LABEL, ignore, r)
    x = 1
    labchk200:
    IF v THEN
        s = Labels(r).Scope
        IF s = subfuncn OR s = -1 THEN 'same scope?
            IF s = -1 THEN Labels(r).Scope = subfuncn 'acquire scope
            x = 0 'already defined
            tlayout$ = RTRIM$(Labels(r).cn)
        ELSE
            IF v = 2 THEN v = HashFindCont(ignore, r): GOTO labchk200
        END IF
    END IF
    IF x THEN
        'does not exist
        nLabels = nLabels + 1: IF nLabels > Labels_Ubound THEN Labels_Ubound = Labels_Ubound * 2: REDIM _PRESERVE Labels(1 TO Labels_Ubound) AS Label_Type
        Labels(nLabels) = Empty_Label
        HashAdd a2$, HASHFLAG_LABEL, nLabels
        r = nLabels
        Labels(r).State = 0
        Labels(r).cn = tlayout$
        Labels(r).Scope = subfuncn
        Labels(r).Error_Line = linenumber
    END IF 'x

    l$ = SCase$("GoSub") + sp + tlayout$
    layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
    'note: This code fragment also used by ON ... GOTO/GOSUB
    'assume label is reachable (revise)
    WriteBufLine MainTxtBuf, "return_point[next_return_point++]=" + _TOSTR$(gosubid) + ";"
    WriteBufLine MainTxtBuf, "if (next_return_point>=return_points) more_return_points();"
    WriteBufLine MainTxtBuf, "goto LABEL_" + a2$ + ";"
    'add return point jump
    WriteBufLine RetTxtBuf, "case " + _TOSTR$(gosubid) + ":"
    WriteBufLine RetTxtBuf, "goto RETURN_" + _TOSTR$(gosubid) + ";"
    WriteBufLine RetTxtBuf, "break;"
    WriteBufLine MainTxtBuf, "RETURN_" + _TOSTR$(gosubid) + ":;"
    gosubid = gosubid + 1
END SUB

SUB xongotogosub (a$, ca$, n)
    IF n < 4 THEN Give_Error "Expected ON expression GOTO/GOSUB label,label,...": EXIT SUB
    l$ = SCase$("On")
    b = 0
    FOR i = 2 TO n
        e2$ = getelement$(a$, i)
        IF e2$ = "(" THEN b = b + 1
        IF e2$ = ")" THEN b = b - 1
        IF e2$ = "GOTO" OR e2$ = "GOSUB" THEN EXIT FOR
    NEXT
    IF i >= n OR i = 2 THEN Give_Error "Expected ON expression GOTO/GOSUB label,label,...": EXIT SUB
    e$ = getelements$(ca$, 2, i - 1)

    g = 0: IF e2$ = "GOSUB" THEN g = 1
    e$ = fixoperationorder(e$)
    IF Error_Happened THEN EXIT SUB
    l$ = l$ + sp + tlayout$
    e$ = evaluate(e$, typ)
    IF Error_Happened THEN EXIT SUB
    IF (typ AND ISREFERENCE) THEN e$ = refer(e$, typ, 0)
    IF Error_Happened THEN EXIT SUB
    IF (typ AND ISSTRING) THEN Give_Error "Expected numeric expression": EXIT SUB
    IF (typ AND ISFLOAT) THEN
        e$ = "qbr_float_to_long(" + e$ + ")"
    END IF
    l$ = l$ + sp + e2$
    u$ = _TOSTR$(uniquenumber)
    WriteBufLine DataTxtBuf, "static int32 ongo_" + u$ + "=0;"
    WriteBufLine MainTxtBuf, "ongo_" + u$ + "=" + e$ + ";"
    ln = 1
    labelwaslast = 0
    FOR i = i + 1 TO n
        e$ = getelement$(ca$, i)
        IF e$ = "," THEN
            l$ = l$ + sp2 + ","
            IF i = n THEN Give_Error "Trailing , invalid": EXIT SUB
            ln = ln + 1
            labelwaslast = 0
        ELSE
            IF labelwaslast THEN Give_Error "Expected ,": EXIT SUB
            IF validlabel(e$) = 0 THEN Give_Error "Invalid label!": EXIT SUB

            v = HashFind(e$, HASHFLAG_LABEL, ignore, r)
            x = 1
            labchk507:
            IF v THEN
                s = Labels(r).Scope
                IF s = subfuncn OR s = -1 THEN 'same scope?
                    IF s = -1 THEN Labels(r).Scope = subfuncn 'acquire scope
                    x = 0 'already defined
                    tlayout$ = RTRIM$(Labels(r).cn)
                ELSE
                    IF v = 2 THEN v = HashFindCont(ignore, r): GOTO labchk507
                END IF
            END IF
            IF x THEN
                'does not exist
                nLabels = nLabels + 1: IF nLabels > Labels_Ubound THEN Labels_Ubound = Labels_Ubound * 2: REDIM _PRESERVE Labels(1 TO Labels_Ubound) AS Label_Type
                Labels(nLabels) = Empty_Label
                HashAdd e$, HASHFLAG_LABEL, nLabels
                r = nLabels
                Labels(r).State = 0
                Labels(r).cn = tlayout$
                Labels(r).Scope = subfuncn
                Labels(r).Error_Line = linenumber
            END IF 'x

            l$ = l$ + sp + tlayout$
            IF g THEN 'gosub
                lb$ = e$
                WriteBufLine MainTxtBuf, "if (ongo_" + u$ + "==" + _TOSTR$(ln) + "){"
                'note: This code fragment also used by ON ... GOTO/GOSUB
                'assume label is reachable (revise)
                WriteBufLine MainTxtBuf, "return_point[next_return_point++]=" + _TOSTR$(gosubid) + ";"
                WriteBufLine MainTxtBuf, "if (next_return_point>=return_points) more_return_points();"
                WriteBufLine MainTxtBuf, "goto LABEL_" + lb$ + ";"
                'add return point jump
                WriteBufLine RetTxtBuf, "case " + _TOSTR$(gosubid) + ":"
                WriteBufLine RetTxtBuf, "goto RETURN_" + _TOSTR$(gosubid) + ";"
                WriteBufLine RetTxtBuf, "break;"
                WriteBufLine MainTxtBuf, "RETURN_" + _TOSTR$(gosubid) + ":;"
                gosubid = gosubid + 1
                WriteBufLine MainTxtBuf, "goto ongo_" + u$ + "_skip;"
                WriteBufLine MainTxtBuf, "}"
            ELSE 'goto
                WriteBufLine MainTxtBuf, "if (ongo_" + u$ + "==" + _TOSTR$(ln) + ") goto LABEL_" + e$ + ";"
            END IF
            labelwaslast = 1
        END IF
    NEXT
    WriteBufLine MainTxtBuf, "if (ongo_" + u$ + "<0) error(5);"
    IF g = 1 THEN WriteBufLine MainTxtBuf, "ongo_" + u$ + "_skip:;"
    layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
END SUB

SUB xprint (a$, ca$, n)
    u$ = _TOSTR$(uniquenumber)

    l$ = SCase$("Print")
    IF ASC(a$) = 76 THEN lp = 1: lp$ = "l": l$ = SCase$("LPrint"): WriteBufLine MainTxtBuf, "tab_LPRINT=1;": SetDependency DEPENDENCY_PRINTER '"L"

    'PRINT USING?
    IF n >= 2 THEN
        IF getelement(a$, 2) = "USING" THEN
            'get format string
            i = 3
            pujump:
            l$ = l$ + sp + SCase$("Using")
            e$ = "": b = 0: puformat$ = ""
            FOR i = i TO n
                a2$ = getelement(ca$, i)
                IF a2$ = "(" THEN b = b + 1
                IF a2$ = ")" THEN b = b - 1
                IF b = 0 THEN
                    IF a2$ = "," THEN Give_Error "Expected PRINT USING formatstring ; ...": EXIT SUB
                    IF a2$ = ";" THEN
                        e$ = fixoperationorder$(e$)
                        IF Error_Happened THEN EXIT SUB
                        l$ = l$ + sp + tlayout$ + sp2 + ";"
                        e$ = evaluate(e$, typ)
                        IF Error_Happened THEN EXIT SUB
                        IF (typ AND ISREFERENCE) THEN e$ = refer(e$, typ, 0)
                        IF Error_Happened THEN EXIT SUB
                        IF (typ AND ISSTRING) = 0 THEN Give_Error "Expected PRINT USING formatstring ; ...": EXIT SUB
                        puformat$ = e$
                        EXIT FOR
                    END IF ';
                END IF 'b
                IF LEN(e$) THEN e$ = e$ + sp + a2$ ELSE e$ = a2$
            NEXT
            IF puformat$ = "" THEN Give_Error "Expected PRINT USING formatstring ; ...": EXIT SUB
            IF i = n THEN Give_Error "Expected PRINT USING formatstring ; ...": EXIT SUB
            'create build string
            IF TQBSset = 0 THEN
                WriteBufLine MainTxtBuf, "tqbs=qbs_new(0,0);"
            ELSE
                WriteBufLine MainTxtBuf, "qbs_set(tqbs,qbs_new_txt_len(" + CHR$(34) + CHR$(34) + ",0));"
            END IF
            'set format start/index variable
            WriteBufLine MainTxtBuf, "tmp_long=0;" 'scan format from beginning


            'create string to hold format in for multiple references
            puf$ = "print_using_format" + u$
            IF subfunc = "" THEN
                WriteBufLine DataTxtBuf, "static qbs *" + puf$ + ";"
            ELSE
                WriteBufLine DataTxtBuf, "qbs *" + puf$ + ";"
            END IF
            WriteBufLine MainTxtBuf, puf$ + "=qbs_new(0,0); qbs_set(" + puf$ + "," + puformat$ + ");"
            WriteBufLine MainTxtBuf, "if (is_error_pending()) goto skip_pu" + u$ + ";"

            'print expressions
            b = 0
            e$ = ""
            last = 0
            FOR i = i + 1 TO n
                a2$ = getelement(ca$, i)
                IF a2$ = "(" THEN b = b + 1
                IF a2$ = ")" THEN b = b - 1
                IF b = 0 THEN
                    IF a2$ = ";" OR a2$ = "," THEN
                        printulast:
                        e$ = fixoperationorder$(e$)
                        IF Error_Happened THEN EXIT SUB
                        IF last THEN l$ = l$ + sp + tlayout$ ELSE l$ = l$ + sp + tlayout$ + sp2 + a2$
                        e$ = evaluate(e$, typ)
                        IF Error_Happened THEN EXIT SUB
                        IF (typ AND ISREFERENCE) THEN e$ = refer(e$, typ, 0)
                        IF Error_Happened THEN EXIT SUB
                        IF typ AND ISSTRING THEN

                            IF LEFT$(e$, 9) = "func_tab(" OR LEFT$(e$, 9) = "func_spc(" THEN

                                'TAB/SPC exception
                                'note: position in format-string must be maintained
                                '-print any string up until now
                                WriteBufLine MainTxtBuf, "qbs_" + lp$ + "print(tqbs,0);"
                                '-print e$
                                WriteBufLine MainTxtBuf, "qbs_set(tqbs," + e$ + ");"
                                WriteBufLine MainTxtBuf, "if (is_error_pending()) goto skip_pu" + u$ + ";"
                                IF lp THEN WriteBufLine MainTxtBuf, "lprint_makefit(tqbs);" ELSE WriteBufLine MainTxtBuf, "makefit(tqbs);"
                                WriteBufLine MainTxtBuf, "qbs_" + lp$ + "print(tqbs,0);"
                                '-set length of tqbs to 0
                                WriteBufLine MainTxtBuf, "tqbs->len=0;"

                            ELSE

                                'regular string
                                WriteBufLine MainTxtBuf, "tmp_long=print_using(" + puf$ + ",tmp_long,tqbs," + e$ + ");"

                            END IF



                        ELSE 'not a string
                            IF typ AND ISFLOAT THEN
                                IF (typ AND UDTMASK) = 32 THEN WriteBufLine MainTxtBuf, "tmp_long=print_using_single(" + puf$ + "," + e$ + ",tmp_long,tqbs);"
                                IF (typ AND UDTMASK) = 64 THEN WriteBufLine MainTxtBuf, "tmp_long=print_using_double(" + puf$ + "," + e$ + ",tmp_long,tqbs);"
                                IF (typ AND UDTMASK) > 64 THEN WriteBufLine MainTxtBuf, "tmp_long=print_using_float(" + puf$ + "," + e$ + ",tmp_long,tqbs);"
                            ELSE
                                IF ((typ AND UDTMASK) = 64) AND (typ AND ISUNSIGNED) <> 0 THEN
                                    WriteBufLine MainTxtBuf, "tmp_long=print_using_uinteger64(" + puf$ + "," + e$ + ",tmp_long,tqbs);"
                                ELSE
                                    WriteBufLine MainTxtBuf, "tmp_long=print_using_integer64(" + puf$ + "," + e$ + ",tmp_long,tqbs);"
                                END IF
                            END IF
                        END IF 'string/not string
                        WriteBufLine MainTxtBuf, "if (is_error_pending()) goto skip_pu" + u$ + ";"
                        e$ = ""
                        IF last THEN EXIT FOR
                        GOTO printunext
                    END IF
                END IF
                IF LEN(e$) THEN e$ = e$ + sp + a2$ ELSE e$ = a2$
                printunext:
            NEXT
            IF e$ <> "" THEN a2$ = "": last = 1: GOTO printulast
            WriteBufLine MainTxtBuf, "skip_pu" + u$ + ":"
            'check for errors
            WriteBufLine MainTxtBuf, "if (is_error_pending()){"
            WriteBufLine MainTxtBuf, "g_tmp_long=new_error; new_error=0; qbs_" + lp$ + "print(tqbs,0); new_error=g_tmp_long;"
            WriteBufLine MainTxtBuf, "}else{"
            IF a2$ = "," OR a2$ = ";" THEN nl = 0 ELSE nl = 1 'note: a2$ is set to the last element of a$
            WriteBufLine MainTxtBuf, "qbs_" + lp$ + "print(tqbs," + _TOSTR$(nl) + ");"
            WriteBufLine MainTxtBuf, "}"
            WriteBufLine MainTxtBuf, "qbs_free(tqbs);"
            WriteBufLine MainTxtBuf, "qbs_free(" + puf$ + ");"
            WriteBufLine MainTxtBuf, "skip" + u$ + ":"
            WriteBufLine MainTxtBuf, cleanupstringprocessingcall$ + "0);"
            IF lp THEN WriteBufLine MainTxtBuf, "tab_LPRINT=0;"
            tlayout$ = l$
            EXIT SUB
        END IF
    END IF
    'end of print using code

    b = 0
    e$ = ""
    last = 0
    WriteBufLine MainTxtBuf, "tqbs=qbs_new(0,0);" 'initialize the temp string
    TQBSset = -1 'set the temporary flag so we don't create a temp string twice, in case USING comes after something
    FOR i = 2 TO n
        a2$ = getelement(ca$, i)
        IF a2$ = "(" THEN b = b + 1
        IF a2$ = ")" THEN b = b - 1
        IF b = 0 THEN
            IF a2$ = ";" OR a2$ = "," OR UCASE$(a2$) = "USING" THEN
                printlast:

                IF UCASE$(a2$) = "USING" THEN
                    IF e$ <> "" THEN gotopu = 1 ELSE i = i + 1: GOTO pujump
                END IF

                IF LEN(e$) THEN
                    ebak$ = e$
                    pnrtnum = 0
                    printnumber:
                    e$ = fixoperationorder$(e$)
                    IF Error_Happened THEN EXIT SUB
                    IF pnrtnum = 0 THEN
                        IF last THEN
                            l$ = l$ + sp + tlayout$
                        ELSEIF gotopu THEN
                            l$ = l$ + sp + tlayout$
                        ELSE
                            l$ = l$ + sp + tlayout$ + sp2 + a2$
                        END IF
                    END IF
                    e$ = evaluate(e$, typ)
                    IF Error_Happened THEN EXIT SUB
                    IF (typ AND ISSTRING) = 0 THEN
                        'not a string expression!
                        e$ = "STR$" + sp + "(" + sp + ebak$ + sp + ")" + sp + "+" + sp + CHR$(34) + " " + CHR$(34)
                        pnrtnum = 1
                        GOTO printnumber
                    END IF
                    IF (typ AND ISREFERENCE) THEN e$ = refer(e$, typ, 0)
                    IF Error_Happened THEN EXIT SUB
                    WriteBufLine MainTxtBuf, "qbs_set(tqbs," + e$ + ");"
                    WriteBufLine MainTxtBuf, "if (is_error_pending()) goto skip" + u$ + ";"
                    IF lp THEN WriteBufLine MainTxtBuf, "lprint_makefit(tqbs);" ELSE WriteBufLine MainTxtBuf, "makefit(tqbs);"
                    WriteBufLine MainTxtBuf, "qbs_" + lp$ + "print(tqbs,0);"
                ELSE
                    IF a2$ = "," THEN l$ = l$ + sp + a2$
                    IF a2$ = ";" THEN
                        IF RIGHT$(l$, 1) <> ";" THEN l$ = l$ + sp + a2$ 'concat ;; to ;
                    END IF
                END IF 'len(e$)
                IF a2$ = "," THEN WriteBufLine MainTxtBuf, "tab();"
                e$ = ""

                IF gotopu THEN i = i + 1: GOTO pujump

                IF last THEN
                    WriteBufLine MainTxtBuf, "qbs_" + lp$ + "print(nothingstring,1);" 'go to new line
                    EXIT FOR
                END IF

                GOTO printnext
            END IF 'a2$
        END IF 'b=0

        IF LEN(e$) THEN e$ = e$ + sp + a2$ ELSE e$ = a2$
        printnext:
    NEXT
    IF LEN(e$) THEN a2$ = "": last = 1: GOTO printlast
    IF n = 1 THEN WriteBufLine MainTxtBuf, "qbs_" + lp$ + "print(nothingstring,1);"
    WriteBufLine MainTxtBuf, "skip" + u$ + ":"
    WriteBufLine MainTxtBuf, "qbs_free(tqbs);"
    WriteBufLine MainTxtBuf, cleanupstringprocessingcall$ + "0);"
    IF lp THEN WriteBufLine MainTxtBuf, "tab_LPRINT=0;"
    tlayout$ = l$
END SUB




SUB xread (ca$, n)
    l$ = SCase$("Read")
    IF n = 1 THEN Give_Error "Expected variable": EXIT SUB
    i = 2
    IF i > n THEN Give_Error "Expected , ...": EXIT SUB
    a3$ = ""
    b = 0
    FOR i = i TO n
        a2$ = getelement$(ca$, i)
        IF a2$ = "(" THEN b = b + 1
        IF a2$ = ")" THEN b = b - 1
        IF (a2$ = "," AND b = 0) OR i = n THEN
            IF i = n THEN
                IF a3$ = "" THEN a3$ = a2$ ELSE a3$ = a3$ + sp + a2$
            END IF
            IF a3$ = "" THEN Give_Error "Expected , ...": EXIT SUB
            e$ = fixoperationorder$(a3$)
            IF Error_Happened THEN EXIT SUB
            l$ = l$ + sp + tlayout$: IF i <> n THEN l$ = l$ + sp2 + ","
            e$ = evaluate(e$, t)
            IF Error_Happened THEN EXIT SUB
            IF (t AND ISREFERENCE) = 0 THEN Give_Error "Expected variable": EXIT SUB

            IF (t AND ISSTRING) THEN
                e$ = refer(e$, t, 0)
                IF Error_Happened THEN EXIT SUB
                WriteBufLine MainTxtBuf, "sub_read_string(data,&data_offset,data_size," + e$ + ");"
                stringprocessinghappened = 1
            ELSE
                'numeric variable
                IF (t AND ISFLOAT) <> 0 OR (t AND UDTMASK) <> 64 THEN
                    IF (t AND ISOFFSETINBITS) THEN
                        setrefer e$, t, "((int64)func_read_float(data,&data_offset,data_size," + _TOSTR$(t) + "))", 1
                        IF Error_Happened THEN EXIT SUB
                    ELSE
                        setrefer e$, t, "func_read_float(data,&data_offset,data_size," + _TOSTR$(t) + ")", 1
                        IF Error_Happened THEN EXIT SUB
                    END IF
                ELSE
                    IF t AND ISUNSIGNED THEN
                        setrefer e$, t, "func_read_uint64(data,&data_offset,data_size)", 1
                        IF Error_Happened THEN EXIT SUB
                    ELSE
                        setrefer e$, t, "func_read_int64(data,&data_offset,data_size)", 1
                        IF Error_Happened THEN EXIT SUB
                    END IF
                END IF
            END IF 'string/numeric
            IF i = n THEN EXIT FOR
            a3$ = "": a2$ = ""
        END IF
        IF a3$ = "" THEN a3$ = a2$ ELSE a3$ = a3$ + sp + a2$
    NEXT
    IF stringprocessinghappened THEN WriteBufLine MainTxtBuf, cleanupstringprocessingcall$ + "0);"
    layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
END SUB

SUB xwrite (ca$, n)
    l$ = SCase$("Write")
    u$ = _TOSTR$(uniquenumber)
    IF n = 1 THEN
        WriteBufLine MainTxtBuf, "qbs_print(nothingstring,1);"
        GOTO writeblankline2
    END IF
    b = 0
    e$ = ""
    last = 0
    FOR i = 2 TO n
        a2$ = getelement(ca$, i)
        IF a2$ = "(" THEN b = b + 1
        IF a2$ = ")" THEN b = b - 1
        IF b = 0 THEN
            IF a2$ = "," THEN
                writelast:
                IF last = 1 THEN newline = 1 ELSE newline = 0
                ebak$ = e$
                reevaled = 0
                writechecked:
                e$ = fixoperationorder$(e$)
                IF Error_Happened THEN EXIT SUB
                IF reevaled = 0 THEN
                    l$ = l$ + sp + tlayout$
                    IF last = 0 THEN l$ = l$ + sp2 + ","
                END IF
                e$ = evaluate(e$, typ)
                IF Error_Happened THEN EXIT SUB
                IF reevaled = 0 THEN
                    IF (typ AND ISSTRING) = 0 THEN
                        e$ = "LTRIM$" + sp + "(" + sp + "STR$" + sp + "(" + sp + ebak$ + sp + ")" + sp + ")"
                        IF last = 0 THEN e$ = e$ + sp + "+" + sp + CHR$(34) + "," + CHR$(34) + ",1"
                        reevaled = 1
                        GOTO writechecked 'force re-evaluation
                    ELSE
                        e$ = CHR$(34) + "\042" + CHR$(34) + ",1" + sp + "+" + sp + ebak$ + sp + "+" + sp + CHR$(34) + "\042" + CHR$(34) + ",1"
                        IF last = 0 THEN e$ = e$ + sp + "+" + sp + CHR$(34) + "," + CHR$(34) + ",1"
                        reevaled = 1
                        GOTO writechecked 'force re-evaluation
                    END IF
                END IF
                IF (typ AND ISREFERENCE) THEN e$ = refer(e$, typ, 0)
                IF Error_Happened THEN EXIT SUB
                'format: string, (1/0) extraspace, (1/0) tab, (1/0)begin a new line
                WriteBufLine MainTxtBuf, "qbs_print(" + e$ + "," + STR$(newline) + ");"
                WriteBufLine MainTxtBuf, "if (is_error_pending()) goto skip" + u$ + ";"
                e$ = ""
                IF last THEN EXIT FOR
                GOTO writenext
            END IF ',
        END IF 'b=0
        IF e$ <> "" THEN e$ = e$ + sp + a2$ ELSE e$ = a2$
        writenext:
    NEXT
    IF e$ <> "" THEN a2$ = ",": last = 1: GOTO writelast
    writeblankline2:
    WriteBufLine MainTxtBuf, "skip" + u$ + ":"
    WriteBufLine MainTxtBuf, cleanupstringprocessingcall$ + "0);"
    layoutdone = 1: IF LEN(layout$) THEN layout$ = layout$ + sp + l$ ELSE layout$ = l$
END SUB

SUB lineinput3load (f$)
    OPEN f$ FOR BINARY AS #1
    l = LOF(1)
    lineinput3buffer$ = SPACE$(l)
    GET #1, , lineinput3buffer$
    IF LEN(lineinput3buffer$) THEN IF RIGHT$(lineinput3buffer$, 1) = CHR$(26) THEN lineinput3buffer$ = LEFT$(lineinput3buffer$, LEN(lineinput3buffer$) - 1)
    CLOSE #1
    lineinput3index = 1
END SUB

FUNCTION lineinput3$
    'returns CHR$(13) if no more lines are available
    l = LEN(lineinput3buffer$)
    IF lineinput3index > l THEN lineinput3$ = CHR$(13): EXIT FUNCTION
    c13 = INSTR(lineinput3index, lineinput3buffer$, CHR$(13))
    c10 = INSTR(lineinput3index, lineinput3buffer$, CHR$(10))
    IF c10 = 0 AND c13 = 0 THEN
        lineinput3$ = MID$(lineinput3buffer$, lineinput3index, l - lineinput3index + 1)
        lineinput3index = l + 1
        EXIT FUNCTION
    END IF
    IF c10 = 0 THEN c10 = 2147483647
    IF c13 = 0 THEN c13 = 2147483647
    IF c10 < c13 THEN
        '10 before 13
        lineinput3$ = MID$(lineinput3buffer$, lineinput3index, c10 - lineinput3index)
        lineinput3index = c10 + 1
        IF lineinput3index <= l THEN
            IF ASC(MID$(lineinput3buffer$, lineinput3index, 1)) = 13 THEN lineinput3index = lineinput3index + 1
        END IF
    ELSE
        '13 before 10
        lineinput3$ = MID$(lineinput3buffer$, lineinput3index, c13 - lineinput3index)
        lineinput3index = c13 + 1
        IF lineinput3index <= l THEN
            IF ASC(MID$(lineinput3buffer$, lineinput3index, 1)) = 10 THEN lineinput3index = lineinput3index + 1
        END IF
    END IF
END FUNCTION


' This function is related to $EMBED, it converts the given file into
' an C-Array incl. read back function and append it to the C/C++ source
' file "internal\temp\embedded.cpp".
'
' Inputs: sourcefile spec, unique handle (case sensitive)
' Return: 0 = normal embed, 1 = packed embed (DEPENDENCY_ZLIB required)
FUNCTION ConvertFileToCArray% (file$, handle$)
    '--- read file contents ---
    sff% = FREEFILE
    filedata$ = _READFILE$(file$)
    '--- try to compress ---
    compdata$ = _DEFLATE$(filedata$)
    IF LEN(compdata$) < (LEN(filedata$) * 0.8) THEN
        tmpfile$ = tmpdir$ + "embed.bin"
        _WRITEFILE tmpfile$, compdata$
        packed% = 1
        OPEN "B", #sff%, tmpfile$
    ELSE
        packed% = 0
        OPEN "B", #sff%, file$
    END IF
    '--- init variables ---
    fl& = LOF(sff%)
    cntL& = INT(fl& / 32)
    cntV& = INT(cntL& / 8180)
    cntB& = (fl& - (cntL& * 32))
    '--- create C-Array ---
    dff% = FREEFILE
    OPEN "A", #dff%, tmpdir$ + "embedded.cpp"
    '--- process LONGs ---
    tmpI$ = SPACE$(32)
    FOR vc& = 0 TO cntV&
        IF vc& = cntV& THEN numL& = (cntL& MOD 8180): ELSE numL& = 8180
        PRINT #dff%, "static const uint32_t "; handle$; "L"; _TOSTR$(vc&); "[] = {"
        PRINT #dff%, "    "; _TOSTR$(numL& * 8); ","
        FOR z& = 1 TO numL&
            GET #sff%, , tmpI$: offI% = 1
            tmpO$ = "    " + STRING$(88, ","): offO% = 5
            DO
                tmpL& = CVL(MID$(tmpI$, offI%, 4)): offI% = offI% + 4
                MID$(tmpO$, offO%, 10) = "0x" + RIGHT$("00000000" + HEX$(tmpL&), 8)
                offO% = offO% + 11
            LOOP UNTIL offO% > 92
            IF z& < numL& THEN PRINT #dff%, tmpO$: ELSE PRINT #dff%, LEFT$(tmpO$, 91)
        NEXT z&
        PRINT #dff%, "};"
        PRINT #dff%, ""
    NEXT vc&
    '--- process remaining BYTEs ---
    IF cntB& > 0 THEN
        PRINT #dff%, "static const uint8_t "; handle$; "B[] = {"
        PRINT #dff%, "    "; _TOSTR$(cntB&); ","
        PRINT #dff%, "    ";
        FOR x% = 1 TO cntB&
            GET #sff%, , tmpB%%
            PRINT #dff%, "0x" + RIGHT$("00" + HEX$(tmpB%%), 2);
            IF x% <> 16 THEN
                IF x% <> cntB& THEN PRINT #dff%, ",";
            ELSE
                IF x% <> cntB& THEN
                    PRINT #dff%, ","
                    PRINT #dff%, "    ";
                END IF
            END IF
        NEXT x%
        PRINT #dff%, ""
        PRINT #dff%, "};"
        PRINT #dff%, ""
    END IF
    '--- make a read function ---
    PRINT #dff%, "qbs *GetArrayData_"; handle$; "(void)"
    PRINT #dff%, "{"
    PRINT #dff%, "    qbs  *data = qbs_new("; _TOSTR$(fl&); ", 1);"
    PRINT #dff%, "    char *buff = (char*) data -> chr;"
    PRINT #dff%, ""
    FOR vc& = 0 TO cntV&
        PRINT #dff%, "    memcpy(buff, &"; handle$; "L"; _TOSTR$(vc&); "[1], "; handle$; "L"; _TOSTR$(vc&); "[0] << 2);"
        IF vc& < cntV& OR cntB& > 0 THEN
            PRINT #dff%, "    buff += ("; handle$; "L"; _TOSTR$(vc&); "[0] << 2);"
        END IF
    NEXT vc&
    IF cntB& > 0 THEN
        PRINT #dff%, "    memcpy(buff, &"; handle$; "B[1], "; handle$; "B[0]);"
    END IF
    PRINT #dff%, ""
    IF packed% THEN
        PRINT #dff%, "    return func__inflate(data, "; _TOSTR$(LEN(filedata$)); ", 1);"
    ELSE
        PRINT #dff%, "    return data;"
    END IF
    PRINT #dff%, "}"
    PRINT #dff%, ""
    '--- ending ---
    CLOSE #dff%
    CLOSE #sff%
    ConvertFileToCArray% = packed%
END FUNCTION


SUB SetDependency (requirement)
    IF requirement THEN
        DEPENDENCY(requirement) = 1
        IF requirement = DEPENDENCY_SOCKETS THEN SetRCStateVar SockDepOn, 1
    END IF
END SUB



FUNCTION QuotedFilename$ (f$)

    IF os$ = "WIN" THEN
        QuotedFilename$ = CHR$(34) + f$ + CHR$(34)
        EXIT FUNCTION
    END IF

    IF os$ = "LNX" THEN
        QuotedFilename$ = "'" + f$ + "'"
        EXIT FUNCTION
    END IF

END FUNCTION

FUNCTION removecast$ (a$)
    removecast$ = a$
    IF INSTR(a$, "  )") THEN
        removecast$ = RIGHT$(a$, LEN(a$) - INSTR(a$, "  )") - 2)
    END IF
END FUNCTION

FUNCTION converttabs$ (a2$)
    IF IDEAutoIndent THEN s = IDEAutoIndentSize ELSE s = 4
    a$ = a2$
    DO WHILE INSTR(a$, CHR_TAB)
        x = INSTR(a$, CHR_TAB)
        a$ = LEFT$(a$, x - 1) + SPACE$(s - ((x - 1) MOD s)) + RIGHT$(a$, LEN(a$) - x)
    LOOP
    converttabs$ = a$
END FUNCTION


FUNCTION NewByteElement$
    a$ = "byte_element_" + _TOSTR$(uniquenumber)
    NewByteElement$ = a$
    IF use_global_byte_elements THEN
        WriteBufLine GlobTxtBuf, "byte_element_struct *" + a$ + "=(byte_element_struct*)malloc(12);"
    ELSE
        WriteBufLine DataTxtBuf, "byte_element_struct *" + a$ + "=NULL;"
        WriteBufLine DataTxtBuf, "if (!" + a$ + "){"
        WriteBufLine DataTxtBuf, "if ((mem_static_pointer+=12)<mem_static_limit) " + a$ + "=(byte_element_struct*)(mem_static_pointer-12); else " + a$ + "=(byte_element_struct*)mem_static_malloc(12);"
        WriteBufLine DataTxtBuf, "}"
    END IF
END FUNCTION

FUNCTION validname (a$)
    'notes:
    '1) '_1' is invalid because it has no alphabet letters
    '2) 'A_' is invalid because it has a trailing _
    '3) '_1A' is invalid because it contains a number before the first alphabet letter
    '4) names cannot be longer than 40 characters
    l = LEN(a$)

    IF l = 0 OR l > 40 THEN
        IF l = 0 THEN EXIT FUNCTION
        'Note: variable names with periods need to be obfuscated, and this affects their length
        i = INSTR(a$, fix046$)
        DO WHILE i
            l = l - LEN(fix046$) + 1
            i = INSTR(i + 1, a$, fix046$)
        LOOP
        IF l > 40 THEN EXIT FUNCTION
        l = LEN(a$)
    END IF

    IF ideprogname$ <> "beforefirstline.bi" AND ideprogname$ <> "afterlastline.bm" THEN
        IF autoIncludingFile <> -1 THEN
            'check for single, leading underscore
            IF l >= 2 THEN
                IF ASC(a$, 1) = 95 AND ASC(a$, 2) <> 95 THEN EXIT FUNCTION
            END IF
        END IF
    ELSE
        IF autoIncludingFile = 0 AND autoIncForceUScore <> 0 THEN
            autoIncForceUScore = 0
            'enforce leading underscore
            IF l >= 1 THEN
                IF ASC(a$, 1) <> 95 THEN EXIT FUNCTION
            END IF
        END IF
    END IF
    autoIncForceUScore = 0

    FOR i = 1 TO l
        a = ASC(a$, i)
        IF alphanumeric(a) = 0 THEN EXIT FUNCTION
        IF isnumeric(a) THEN
            trailingunderscore = 0
            IF alphabetletter = 0 THEN EXIT FUNCTION
        ELSE
            IF a = 95 THEN
                trailingunderscore = 1
            ELSE
                alphabetletter = 1
                trailingunderscore = 0
            END IF
        END IF
    NEXT
    IF trailingunderscore THEN EXIT FUNCTION
    validname = 1
END FUNCTION

FUNCTION str_nth$ (x)
    IF x = 1 THEN str_nth$ = "1st": EXIT FUNCTION
    IF x = 2 THEN str_nth$ = "2nd": EXIT FUNCTION
    IF x = 3 THEN str_nth$ = "3rd": EXIT FUNCTION
    str_nth$ = _TOSTR$(x) + "th"
END FUNCTION

FUNCTION VRGBS~& (text$, DefaultColor AS _UNSIGNED LONG)
    'Value of RGB String = VRGBS without a ton of typing
    'A function to get the RGB value back from a string such as _RGB32(255,255,255)
    'text$ is the string that we send to check for a value
    'DefaultColor is the value we send back if the string isn't in the proper format

    VRGBS~& = DefaultColor 'A return the default value if we can't parse the string properly
    IF UCASE$(LEFT$(text$, 4)) = "_RGB" THEN
        rpos = INSTR(text$, "(")
        gpos = INSTR(rpos, text$, ",")
        bpos = INSTR(gpos + 1, text$, ",")
        IF rpos <> 0 AND bpos <> 0 AND gpos <> 0 THEN
            red = VAL(_TRIM$(MID$(text$, rpos + 1)))
            green = VAL(_TRIM$(MID$(text$, gpos + 1)))
            blue = VAL(_TRIM$(MID$(text$, bpos + 1)))
            VRGBS~& = _RGB32(red, green, blue)
        END IF
    END IF
END FUNCTION

FUNCTION rgbs$ (c AS _UNSIGNED LONG)
    rgbs$ = "_RGB32(" + _TOSTR$(_RED32(c)) + ", " + _TOSTR$(_GREEN32(c)) + ", " + _TOSTR$(_BLUE32(c)) + ")"
END FUNCTION

SUB SetPreLET (flagName$, flagValue$)
    'First look to see if we have an existing setting like this and if so, update it
    FOR i = UserDefineCountPresets + 1 TO UserDefineCount 'exclude OS/BIT/Compiler detection & version
        IF UserDefine(0, i) = flagName$ THEN UserDefine(1, i) = flagValue$: EXIT SUB
    NEXT
    'Otherwise create a new setting and set the initial value for it
    UserDefineCount = UserDefineCount + 1
    IF UserDefineCount > UBOUND(UserDefine, 2) THEN
        REDIM _PRESERVE UserDefine(1, UBOUND(UserDefine, 2) + 10) 'Add another 10 elements to the array so it'll expand as the user adds to it
    END IF
    UserDefine(0, UserDefineCount) = flagName$
    UserDefine(1, UserDefineCount) = flagValue$
    UserDefineList$ = UserDefineList$ + flagName$ + "@" 'for highlighting
END SUB

FUNCTION EvalPreIF (text$, err$)
    temp$ = text$ 'so we don't corrupt the string sent to us for evaluation
    err$ = "" 'null the err message to begin with
    'first order of business is to solve for <>=
    DIM PC_Op(3) AS STRING
    PC_Op(1) = "="
    PC_Op(2) = "<"
    PC_Op(3) = ">"
    DO
        'look for the existence of the first symbol if there is any
        firstsymbol$ = "": first = 0
        FOR i = 1 TO UBOUND(PC_Op)
            temp = INSTR(temp$, PC_Op(i))
            IF first = 0 THEN first = temp: firstsymbol$ = PC_Op(i)
            IF temp <> 0 AND temp < first THEN first = temp: firstsymbol$ = PC_Op(i)
        NEXT
        IF firstsymbol$ <> "" THEN 'we've got = < >; let's see if we have a combination of them
            secondsymbol = 0: second = 0
            FOR i = first + 1 TO LEN(temp$)
                a$ = MID$(temp$, i, 1)
                SELECT CASE a$
                    CASE " " 'ignore spaces
                    CASE "=", "<", ">"
                        IF a$ = firstsymbol$ THEN err$ = "Duplicate operator (" + a$ + ")": EXIT FUNCTION
                        second = i: secondsymbol$ = a$
                    CASE ELSE 'we found a symbol we don't recognize
                        EXIT FOR
                END SELECT
            NEXT
        END IF
        IF first THEN 'we found a symbol
            l$ = RTRIM$(LEFT$(temp$, first - 1))
            IF second THEN rightstart = second + 1 ELSE rightstart = first + 1

            r$ = LTRIM$(MID$(temp$, rightstart))
            symbol$ = MID$(temp$, first, 1) + MID$(temp$, second, 1)
            'now we check for spaces to separate this segment from any other AND/OR conditions and such
            FOR i = LEN(l$) TO 1 STEP -1
                IF ASC(l$, i) = 32 THEN EXIT FOR
            NEXT
            leftside$ = RTRIM$(LEFT$(temp$, i))
            l$ = LTRIM$(RTRIM$(MID$(temp$, i + 1, LEN(l$) - i)))
            rightstop = LEN(r$)
            FOR i = 1 TO LEN(r$)
                IF ASC(r$, i) = 32 THEN EXIT FOR
            NEXT
            rightside$ = LTRIM$(MID$(r$, i + 1))
            r$ = LTRIM$(RTRIM$(LEFT$(r$, i - 1)))
            IF symbol$ = "=<" THEN symbol$ = "<="
            IF symbol$ = "=>" THEN symbol$ = ">="
            IF symbol$ = "><" THEN symbol$ = "<>"
            result$ = " 0 "
            IF symbol$ = "<>" THEN 'check to see if we're NOT equal in any case with <>
                FOR i = 0 TO UserDefineCount
                    IF UserDefine(0, i) = l$ AND UserDefine(1, i) <> r$ THEN result$ = " -1 ": GOTO finishedcheck
                NEXT
            END IF
            IF INSTR(symbol$, "=") THEN 'check to see if we're equal in any case with =
                UserFound = 0
                IF l$ = UserDefine(0, 7) THEN 'we're comparing VERSION numbers
                    result = CompareVersions(Version$, r$) '-1 is less than, 0 is equal, +1 is greater than
                    IF result = 0 THEN result$ = " -1 ": GOTO finishedcheck
                END IF
                FOR i = 0 TO UserDefineCount
                    IF i = 7 THEN _CONTINUE
                    IF UserDefine(0, i) = l$ THEN
                        UserFound = -1
                        IF UserDefine(1, i) = r$ THEN result$ = " -1 ": GOTO finishedcheck
                    END IF
                NEXT
                IF UserFound = 0 AND LTRIM$(RTRIM$(r$)) = "UNDEFINED" THEN result$ = " -1 ": GOTO finishedcheck
                IF UserFound = -1 AND LTRIM$(RTRIM$(r$)) = "DEFINED" THEN result$ = " -1 ": GOTO finishedcheck
            END IF

            IF INSTR(symbol$, ">") THEN 'check to see if we're greater than in any case with >
                IF l$ = UserDefine(0, 7) THEN 'we're comparing VERSION numbers
                    result = CompareVersions(Version$, r$) '-1 is less than, 0 is equal, +1 is greater than
                    IF result = 1 THEN result$ = " -1 ": GOTO finishedcheck
                END IF
                FOR i = 0 TO UserDefineCount
                    IF i = 7 THEN _CONTINUE
                    IF VerifyNumber(r$) AND VerifyNumber(UserDefine(1, i)) THEN 'we're comparing numeric values
                        IF UserDefine(0, i) = l$ AND VAL(UserDefine(1, i)) > VAL(r$) THEN result$ = " -1 ": GOTO finishedcheck
                    ELSE
                        IF UserDefine(0, i) = l$ AND UserDefine(1, i) > r$ THEN result$ = " -1 ": GOTO finishedcheck
                    END IF
                NEXT
            END IF

            IF INSTR(symbol$, "<") THEN 'check to see if we're less than in any case with <
                IF l$ = UserDefine(0, 7) THEN 'we're comparing VERSION numbers
                    result = CompareVersions(Version$, r$) '-1 is less than, 0 is equal, +1 is greater than
                    IF result = -1 THEN result$ = " -1 ": GOTO finishedcheck
                END IF
                FOR i = 0 TO UserDefineCount
                    IF i = 7 THEN _CONTINUE
                    IF VerifyNumber(r$) AND VerifyNumber(UserDefine(1, i)) THEN 'we're comparing numeric values
                        IF UserDefine(0, i) = l$ AND VAL(UserDefine(1, i)) < VAL(r$) THEN result$ = " -1 ": GOTO finishedcheck
                    ELSE
                        IF UserDefine(0, i) = l$ AND UserDefine(1, i) < r$ THEN result$ = " -1 ": GOTO finishedcheck
                    END IF
                NEXT
            END IF

            finishedcheck:
            temp$ = leftside$ + result$ + rightside$
        END IF
    LOOP UNTIL first = 0

    'And at this point we should now be down to a statement with nothing but AND/OR/XORS in it

    PC_Op(1) = " AND "
    PC_Op(2) = " OR "
    PC_Op(3) = " XOR "

    DO
        first = 0
        FOR i = 1 TO UBOUND(PC_Op)
            IF PC_Op(i) <> "" THEN
                t = INSTR(temp$, PC_Op(i))
                IF first <> 0 THEN
                    IF t < first AND t <> 0 THEN first = t: firstsymbol = i
                ELSE
                    first = t: firstsymbol = i
                END IF
            END IF
        NEXT
        IF first = 0 THEN EXIT DO
        leftside$ = RTRIM$(LEFT$(temp$, first - 1))
        symbol$ = MID$(temp$, first, LEN(PC_Op(firstsymbol)))
        t$ = MID$(temp$, first + LEN(PC_Op(firstsymbol)))
        t = INSTR(t$, " ") 'the first space we come to
        IF t THEN
            m$ = LTRIM$(RTRIM$(LEFT$(t$, t - 1)))
            rightside$ = LTRIM$(MID$(t$, t))
        ELSE
            m$ = LTRIM$(MID$(t$, t))
            rightside$ = ""
        END IF
        leftresult = 0
        IF VerifyNumber(leftside$) THEN
            IF VAL(leftside$) <> 0 THEN leftresult = -1
        ELSE
            FOR i = 0 TO UserDefineCount
                IF UserDefine(0, i) = leftside$ THEN
                    t$ = LTRIM$(RTRIM$(UserDefine(1, i)))
                    IF t$ <> "0" AND t$ <> "" THEN leftresult = -1: EXIT FOR
                END IF
            NEXT
        END IF
        rightresult = 0
        IF VerifyNumber(m$) THEN
            IF VAL(m$) <> 0 THEN rightresult = -1
        ELSE
            FOR i = 0 TO UserDefineCount
                IF UserDefine(0, i) = m$ THEN
                    t$ = LTRIM$(RTRIM$(UserDefine(1, i)))
                    IF t$ <> "0" AND t$ <> "" THEN rightresult = -1: EXIT FOR
                END IF
            NEXT
        END IF
        SELECT CASE LTRIM$(RTRIM$(symbol$))
            CASE "AND"
                IF leftresult <> 0 AND rightresult <> 0 THEN result$ = " -1 " ELSE result$ = " 0 "
            CASE "OR"
                IF leftresult <> 0 OR rightresult <> 0 THEN result$ = " -1 " ELSE result$ = " 0 "
            CASE "XOR"
                IF leftresult <> rightresult THEN result$ = " -1 " ELSE result$ = " 0 "
        END SELECT
        temp$ = result$ + rightside$
    LOOP

    IF VerifyNumber(temp$) THEN
        EvalPreIF = VAL(temp$)
    ELSE
        IF INSTR(temp$, " ") THEN err$ = "Invalid Resolution of $IF; check statements" 'If we've got more than 1 statement, it's invalid
        FOR i = 0 TO UserDefineCount
            IF UserDefine(0, i) = temp$ THEN
                t$ = LTRIM$(RTRIM$(UserDefine(1, i)))
                IF t$ <> "0" AND t$ <> "" THEN EvalPreIF = -1: EXIT FOR
            END IF
        NEXT
    END IF

END FUNCTION

FUNCTION VerifyNumber (text$)
    t$ = LTRIM$(RTRIM$(text$))
    v = VAL(t$)
    t1$ = _TOSTR$(v)
    IF t$ = t1$ THEN VerifyNumber = -1
END FUNCTION

SUB manageVariableList (__name$, __cname$, localIndex AS LONG, action AS _BYTE)
    DIM findItem AS LONG, cname$, i AS LONG, j AS LONG, name$, temp$
    name$ = RTRIM$(__name$)
    cname$ = RTRIM$(__cname$)

    IF LEN(cname$) = 0 THEN EXIT SUB

    findItem = INSTR(cname$, "[")
    IF findItem THEN
        cname$ = LEFT$(cname$, findItem - 1)
    END IF

    found = 0
    FOR i = 1 TO totalVariablesCreated
        IF usedVariableList(i).cname = cname$ THEN found = -1: EXIT FOR
    NEXT

    SELECT CASE action
        CASE 0 'add
            IF found = 0 THEN
                IF i > UBOUND(usedVariableList) THEN
                    REDIM _PRESERVE usedVariableList(UBOUND(usedVariableList) + 999) AS usedVarList
                END IF

                usedVariableList(i).id = currentid
                usedVariableList(i).used = 0
                usedVariableList(i).watch = 0
                usedVariableList(i).displayFormat = 0
                usedVariableList(i).storage = ""
                usedVariableList(i).linenumber = linenumber
                usedVariableList(i).includeLevel = inclevel
                IF inclevel > 0 THEN
                    usedVariableList(i).includedLine = inclinenumber(inclevel)
                    thisincname$ = getfilepath$(incname$(inclevel))
                    thisincname$ = MID$(incname$(inclevel), LEN(thisincname$) + 1)
                    usedVariableList(i).includedFile = thisincname$
                ELSE
                    totalMainVariablesCreated = totalMainVariablesCreated + 1
                    usedVariableList(i).includedLine = 0
                    usedVariableList(i).includedFile = ""
                END IF
                usedVariableList(i).scope = subfuncn
                usedVariableList(i).subfunc = subfunc
                usedVariableList(i).varType = id2fulltypename$
                usedVariableList(i).cname = cname$
                usedVariableList(i).localIndex = localIndex

                'remove eventual instances of fix046$ in name$
                DO WHILE INSTR(name$, fix046$)
                    x = INSTR(name$, fix046$): name$ = LEFT$(name$, x - 1) + "." + RIGHT$(name$, LEN(name$) - x + 1 - LEN(fix046$))
                LOOP

                IF LEN(RTRIM$(id.musthave)) > 0 THEN
                    usedVariableList(i).name = name$ + RTRIM$(id.musthave)
                ELSEIF LEN(RTRIM$(id.mayhave)) > 0 THEN
                    usedVariableList(i).name = name$ + RTRIM$(id.mayhave)
                ELSE
                    usedVariableList(i).name = name$
                END IF

                IF (id.arrayelements > 0) THEN
                    usedVariableList(i).isarray = -1
                    usedVariableList(i).name = usedVariableList(i).name + "()"
                ELSE
                    usedVariableList(i).isarray = 0
                END IF
                usedVariableList(i).watchRange = ""
                usedVariableList(i).arrayElementSize = 0
                usedVariableList(i).indexes = ""
                usedVariableList(i).elements = ""
                usedVariableList(i).elementTypes = ""
                usedVariableList(i).elementOffset = ""
                totalVariablesCreated = totalVariablesCreated + 1

                temp$ = MKL$(-1) + MKL$(LEN(cname$)) + cname$
                found = INSTR(backupVariableWatchList$, temp$)
                IF found THEN
                    'this variable existed in a previous edit of this program
                    'in this same session; let's preselect it.
                    j = CVL(MID$(backupVariableWatchList$, found + LEN(temp$), 4))

                    'if there have been changes in TYPEs, this variable won't be preselected
                    IF (LEN(backupUsedVariableList(j).elements) > 0 AND backupTypeDefinitions$ = typeDefinitions$) OR _
                        (LEN(backupUsedVariableList(j).elements) = 0) THEN
                        usedVariableList(i).watch = backupUsedVariableList(j).watch
                        usedVariableList(i).watchRange = backupUsedVariableList(j).watchRange
                        usedVariableList(i).indexes = backupUsedVariableList(j).indexes
                        usedVariableList(i).displayFormat = backupUsedVariableList(j).displayFormat
                        usedVariableList(i).elements = backupUsedVariableList(j).elements
                        usedVariableList(i).elementTypes = backupUsedVariableList(j).elementTypes
                        usedVariableList(i).elementOffset = backupUsedVariableList(j).elementOffset
                    END IF
                END IF
            END IF
        CASE ELSE 'find and mark as used
            IF found THEN
                usedVariableList(i).used = -1
            END IF
    END SELECT
END SUB

SUB addWarning (whichLineNumber AS LONG, includeLevel AS LONG, incLineNumber AS LONG, incFileName$, header$, text$)
    warningsissued = -1
    totalWarnings = totalWarnings + 1

    IF idemode = 0 AND ShowWarnings THEN
        thissource$ = getfilepath$(CMDLineSrcFile$)
        thissource$ = MID$(CMDLineSrcFile$, LEN(thissource$) + 1)
        thisincname$ = getfilepath$(incFileName$)
        thisincname$ = MID$(incFileName$, LEN(thisincname$) + 1)

        IF NOT MonochromeLoggingMode THEN COLOR 15
        IF includeLevel > 0 AND incLineNumber > 0 THEN
            PRINT thisincname$; ":";
            PRINT _TOSTR$(incLineNumber); ": ";
        ELSE
            PRINT thissource$; ":";
            PRINT _TOSTR$(whichLineNumber); ": ";
        END IF

        IF NOT MonochromeLoggingMode THEN COLOR 13
        PRINT "warning: ";
        IF NOT MonochromeLoggingMode THEN COLOR 7
        PRINT header$

        IF LEN(text$) > 0 THEN
            IF NOT MonochromeLoggingMode THEN COLOR 2
            PRINT SPACE$(4); text$
            IF NOT MonochromeLoggingMode THEN COLOR 7
        END IF
    ELSEIF idemode THEN
        IF NOT IgnoreWarnings THEN
            IF whichLineNumber > maxLineNumber THEN maxLineNumber = whichLineNumber
            IF lastWarningHeader <> header$ THEN
                lastWarningHeader = header$
                GOSUB increaseWarningCount
                warning$(warningListItems) = header$
                warningLines(warningListItems) = 0
            END IF

            GOSUB increaseWarningCount
            warning$(warningListItems) = text$
            warningLines(warningListItems) = whichLineNumber
            IF includeLevel > 0 THEN
                thisincname$ = getfilepath$(incFileName$)
                thisincname$ = MID$(incFileName$, LEN(thisincname$) + 1)
                warningIncLines(warningListItems) = incLineNumber
                warningIncFiles(warningListItems) = thisincname$
            ELSE
                warningIncLines(warningListItems) = 0
                warningIncFiles(warningListItems) = ""
            END IF
        END IF
    END IF
    EXIT SUB
    increaseWarningCount:
    warningListItems = warningListItems + 1
    IF warningListItems > UBOUND(warning$) THEN
        REDIM _PRESERVE warning$(warningListItems + 999)
        REDIM _PRESERVE warningLines(warningListItems + 999) AS LONG
        REDIM _PRESERVE warningIncLines(warningListItems + 999) AS LONG
        REDIM _PRESERVE warningIncFiles(warningListItems + 999) AS STRING
    END IF
    RETURN
END SUB

FUNCTION SCase$ (t$)
    SELECT CASE IDEAutoLayoutKwStyle
        CASE IS < 0: SCase$ = LCASE$(t$)
        CASE IS > 0: SCase$ = UCASE$(t$)
        CASE ELSE: SCase$ = t$
    END SELECT
END FUNCTION

FUNCTION SCase2$ (t$)
    'uses global constant "sp" (see source\global\constants.bas)
    SELECT CASE IDEAutoLayoutKwStyle
        CASE IS < 0: SCase2$ = LCASE$(t$)
        CASE IS > 0: SCase2$ = UCASE$(t$)
        CASE ELSE
            SELECT CASE UCASE$(t$)
                CASE "_ANDALSO": SCase2$ = "_AndAlso"
                CASE "_ORELSE": SCase2$ = "_OrElse"
                CASE "_DYNAMIC": SCase2$ = "_Dynamic"
                CASE "_STATIC": SCase2$ = "_Static"
                CASE ELSE
                    newWord = -1
                    temp$ = ""
                    FOR i = 1 TO LEN(t$)
                        s$ = MID$(t$, i, 1)
                        IF newWord THEN
                            IF s$ = "_" OR s$ = sp THEN
                                temp$ = temp$ + s$
                            ELSE
                                temp$ = temp$ + UCASE$(s$)
                                newWord = 0
                            END IF
                        ELSE
                            IF s$ = sp THEN
                                temp$ = temp$ + sp
                                newWord = -1
                            ELSE
                                temp$ = temp$ + LCASE$(s$)
                            END IF
                        END IF
                    NEXT
                    SCase2$ = temp$
            END SELECT
    END SELECT
END FUNCTION

FUNCTION CompareVersions (v$, v1$)
    t$ = v$: t1$ = v1$ 'temp strings so we don't change the passed values
    IF RIGHT$(t$, 8) = "-UNKNOWN" THEN t$ = LEFT$(t$, LEN(t$) - 8)
    IF RIGHT$(t1$, 8) = "-UNKNOWN" THEN t1$ = LEFT$(t1$, LEN(t1$) - 8)
    DO
        l = INSTR(t$, "."): l1 = INSTR(t1$, ".")
        IF l THEN '                       the first value has a period still
            v& = VAL(LEFT$(t$, l - 1)) '  take what's to the left of that period for our value
            t$ = MID$(t$, l + 1) '        strip that period and everything to the left off for the next pass
        ELSE
            v& = VAL(t$) '                no period?  Then this is our final pass
            t$ = ""
        END IF
        IF l1 THEN
            v1& = VAL(LEFT$(t1$, l1 - 1))
            t1$ = MID$(t1$, l1 + 1)
        ELSE
            v1& = VAL(t1$)
            t1$ = ""
        END IF
        IF v& < v1& THEN CompareVersions = -1: EXIT FUNCTION
        IF v& > v1& THEN CompareVersions = 1: EXIT FUNCTION
        IF t$ = "" AND t1$ = "" THEN EXIT FUNCTION 'return value 0 -- they're equal
        IF t$ = "" AND t1$ <> "" THEN CompareVersions = -1: EXIT FUNCTION
        IF t1$ = "" AND t$ <> "" THEN CompareVersions = 1: EXIT FUNCTION
    LOOP
END FUNCTION

'$INCLUDE:'utilities\strings.bas'
'$INCLUDE:'utilities\file.bas'
'$INCLUDE:'utilities\build.bas'
'$INCLUDE:'utilities\elements.bas'
'$INCLUDE:'subs_functions\extensions\opengl\opengl_methods.bas'
'$INCLUDE:'utilities\ini-manager\ini.bm'
'$INCLUDE:'utilities\s-buffer\simplebuffer.bm'
'$INCLUDE:'utilities\const_eval.bas'
'$INCLUDE:'utilities\hash.bas'
'$INCLUDE:'utilities\statevars.bas'
'$INCLUDE:'utilities\type.bas'
'$INCLUDE:'utilities\give_error.bas'
'$INCLUDE:'utilities\format.bas'
'$INCLUDE:'utilities\terminal.bas'
'$INCLUDE:'emit\logging.bas'

DEFLNG A-Z

'-------- Optional IDE Component (2/2) --------
'$INCLUDE:'ide\config\cfg_methods.bas'
'$INCLUDE:'ide\ide_methods.bas'

