BCX error executing the compiler

Started by JimReeder, April 01, 2025, 01:24:00 PM

Previous topic - Next topic

MrBcx

Jim,

The code below is what I originally wanted to provide to you but it did not run correctly.
Specifically:  SUB MINT_TokenizeRoutine

I spent a few hours deep inside the BCX Translator source code, found (and fixed) the bug
that emits the C/C++ code for REDIM involving the passing of arrays of UDTs by reference. 
The code below runs as it should using Pelles C and Microsoft Visual C but it requires
BCX 8.2.7 which won't be released until later this month.  I wanted to let you know.

It was an interesting puzzle that needed to be solved. ;D 


'**************************************************************************
' (April 3, 2025)
' MrBcx refactored Jim Reeder's original BCX code who ported it from PB.
' MrBcx's version requires BCX 8.2.7 to correctly translate and compile.
' Visual C++ and Pelles C produces exe's that run as expected.
' LccWin32, Mingw, and CLANG all produce flawed executables, possibly
' stemming from the GetToken subroutine or aggressive compiler optimizing.
'**************************************************************************

TYPE MINT_TOKEN
    mToken AS STRING
    mTokentype AS LONG
END TYPE

ENUM
    tt_Identifier       '  'a variable name
    tt_Number           '
    tt_QuotedText       '
    tt_SingleQuote      '  '
    tt_DoubleQuote      '  ""
    tt_OpenParam        '  (
    tt_CloseParam       '  )
    tt_OpenBracket      '  [
    tt_CloseBracket     '  ]
    tt_OpenBrace        '  {
    tt_CloseBrace       '  }
    tt_Equal            '  =
    tt_Assignment       '  ^
    tt_BinaryOperator   '  +-*/\
END ENUM


FUNCTION MAIN
    DIM DYNAMIC tokens[0] AS MINT_TOKEN
    DIM AS LONG r, tokenIdx
    DIM AS STRING procText, fileP, fileN, s

    procText = "A[o]+1+5^A[o]*(2+5^B),DO{A+1^A<100 IF{A=50 A^!}};"
    r = MINT_TokenizeRoutine(procText, ADDRESSOF tokens)

    FOR INT i = 1 TO r
        PRINT tokens[i].mToken
    NEXT i
    PRINT
    PAUSE
END FUNCTION

'*************************************************************************************
'
'*************************************************************************************

FUNCTION MINT_TokenizeRoutine(procText AS STRING, BYREF MT AS MINT_TOKEN PTR) AS LONG
    DIM AS PCHAR ep, ip, zeroip
    DIM i AS LONG
    DIM tok AS STRING

    REDIM MT[100] AS MINT_TOKEN

    IF LEN(procText) = 0 THEN procText = WRAP$(WRAP$("MINT")) ' <<-- produces ""MINT""

    ip = procText
    zeroip = ip
    ep = (ip + LEN(procText)- 1)
    i = 0

    WHILE ip <= ep
        GOSUB GetToken
        INCR i
        IF i > UBOUND_D(MT) THEN
            REDIM PRESERVE MT[i+100] AS MINT_TOKEN
        END IF
        MT[i].mToken = tok
    WEND

    FUNCTION = i

    '******************
    ' Begin Subroutine
    '******************
    GetToken:

    tok = ""
    DO
        SELECT CASE ip[0]
            CASE 34
            IF LEN(tok) = 0 THEN
                tok = CHR$(34)
                WHILE ip <= ep
                    INCR ip
                    tok = tok + CHR$(ip[0])
                    IF ip[0] = 34 THEN EXIT DO
                WEND
            END IF
            CASE 0 TO 45, 47, 127 TO 255
            IF LEN(tok) = 0 THEN
                tok = CHR$(ip[0])
                INCR ip
            END IF
            EXIT DO

            CASE 46, 48 TO 57
            tok = tok+CHR$(ip[0])

            CASE 58 TO 63
            IF LEN(tok) = 0 THEN
                tok = CHR$(ip[0])
                INCR ip
            END IF
            EXIT DO

            CASE 64
            tok = tok +"@"
            INCR ip
            WHILE ip <= ep
                SELECT CASE ip[0]
                    CASE 46, 65 TO 90, 97 TO 122
                    tok = tok + CHR$(ip[0])
                    INCR ip
                    REM  !  &  *  +  -  /  <  =  >  \  {
                    CASE 33, 38, 42, 43, 45, 47, 60, 61, 62, 92, 123
                    tok = tok + CHR$(ip[0])
                    INCR ip
                    EXIT WHILE

                    CASE ELSE
                    EXIT WHILE
                END SELECT
            WEND
            EXIT DO

                CASE 46, 65 TO 90, 97 TO 122
            IF (ip+2) < ep THEN
                IF (ip[0] = 68) AND (ip[1] = 79) AND (ip[2] = 123) THEN
                    tok = "DO{"
                    ip = ip + 3
                    EXIT DO
                ELSEIF (ip[0] = 73) AND (ip[1] = 70) AND (ip[2] = 123) THEN
                    tok = "IF{"
                    ip = ip + 3
                    EXIT DO
                END IF
            END IF
            tok = CHR$(ip[0])
            INCR ip
            WHILE ip <= ep
                SELECT CASE ip[0]
                    CASE 46, 48 TO 57, 65 TO 90, 97 TO 122
                    tok = tok + CHR$(ip[0])
                    INCR ip
                    CASE ELSE
                    EXIT WHILE
                END SELECT
            WEND
            EXIT DO

                CASE 91 TO 96
            IF LEN(tok) = 0 THEN
                tok = CHR$(ip[0])
                INCR ip
            END IF
            EXIT DO

                CASE ELSE
            IF LEN(tok) = 0 THEN
                tok = CHR$(ip[0])
                INCR ip
            END IF
            EXIT DO
        END SELECT

        IF ip <= ep THEN
            INCR ip
        ELSE
            EXIT DO
        END IF

    LOOP
    RETURN  ' return from subroutine
END FUNCTION



JimReeder

#10
Ah, I see the problem, it is the path name.  The correct path has c:\!Dev\..  The "!" is being dropped.

I changed the root path to c:\MINTBED\Src and it completed successfully.
Interesting issue with the ! in a pathname.  I have never encountered such an issue as this.

I will say, the problem caused me to come to the forum and I learned a lot more than if I had seen the pathname issue right off. :)


Robert

Quote from: JimReeder on April 01, 2025, 08:27:31 PMUgh.. I still receive the same error.  I copied your solution, and when I Build it, I get:

BCX BASIC to C/C++ Translator (c) 1999-2025 by Kevin Diggins
Version 8.2.6 (03/21/2025) Compiled using LLVM-Clang (20.1.0) for 64-bit Windows
[Lines In: 180] [Lines Out: 788] [Statements: 151] [Time: 0.02 Sec's]
BCX translated [Bd_Mint_Parser.Bas] to [Bd_Mint_Parser.C] for a C Compiler
ERROR: "C:\Dev\MINTBED\Src\bd_Mint_parser".c was not found. Operation aborted.

Hi Jim:
Welcome to BCX.
Please change the filename to BdMintParser.Bas. No underscores.
Let us know if that works.
"%~dpn1.c" in the batch files has a quirk with filenames with more than one (.) dot. Perhaps there's a problem with underscores.

JimReeder

Ugh.. I still receive the same error.  I copied your solution, and when I Build it, I get:

BCX BASIC to C/C++ Translator (c) 1999-2025 by Kevin Diggins
Version 8.2.6 (03/21/2025) Compiled using LLVM-Clang (20.1.0) for 64-bit Windows
[Lines In: 180] [Lines Out: 788] [Statements: 151] [Time: 0.02 Sec's]
BCX translated [Bd_Mint_Parser.Bas] to [Bd_Mint_Parser.C] for a C Compiler
ERROR: "C:\Dev\MINTBED\Src\bd_Mint_parser".c was not found. Operation aborted.

JimReeder

Thank you!.  I see and understand what you did.  I have found it difficult of find specific things within the BCX documentation.  I am using the latest BCX help file.  My usage of c is weak, which may account for my issues in finding or understanding the documentation.  I fully understand pointers and structures, but I am weak in the c representations.

I will keep at it.  :)



MrBcx

Below is a (more or less) working BCX version.  It compiles and runs using Pelles, MSVC,
and Clang but Lcc-Win32 and Mingw both hang when the demo is run. 

The biggest change was that I needed to make tokens[] a global dynamic array of MINT_TOKEN.
I removed a lot of unneeded stuff, such as your copious use of BYTE_AT.  It should make
your code much easier to read now.


TYPE MINT_TOKEN
    mToken AS STRING
    mTokentype AS LONG
END TYPE

ENUM
    tt_Identifier       '  'a variable name
    tt_Number           '
    tt_QuotedText       '
    tt_SingleQuote      '  '
    tt_DoubleQuote      '  ""
    tt_OpenParam        '  (
    tt_CloseParam       '  )
    tt_OpenBracket      '  [
    tt_CloseBracket     '  ]
    tt_OpenBrace        '  {
    tt_CloseBrace       '  }
    tt_Equal            '  =
    tt_Assignment       '  ^
    tt_BinaryOperator   '  +-*/\
END ENUM


FUNCTION MAIN
    GLOBAL DYNAMIC tokens[1] AS MINT_TOKEN
    DIM i AS LONG, r AS LONG
    DIM tokenIdx AS LONG
    DIM procText AS STRING
    DIM fileP AS STRING
    DIM fileN AS STRING
    DIM s AS STRING

    procText = "A[o]+1+5^A[o]*(2+5^B),DO{A+1^A<100 IF{A=50 A^!}};"

    r = MINT_TokenizeRoutine(procText)

    FOR i = 1 TO r
        PRINT tokens[i].mToken
    NEXT i
    PRINT
    PRINT "Press any key to exit"
    KEYPRESS
END FUNCTION

'***********************************************************************************************
'
'***********************************************************************************************

FUNCTION MINT_TokenizeRoutine(procText AS STRING) AS LONG

    DIM tok AS STRING
    DIM ip AS PCHAR
    DIM zeroip AS PCHAR
    DIM ep AS PCHAR
    DIM i AS LONG

    REDIM tokens[100]

    IF LEN(procText) = 0 THEN procText= WRAP$(WRAP$("MINT")) ' <<-- produces ""MINT""

    ip = procText
    zeroip = ip
    ep = ip + LEN(procText)- 1
    i = 0
    WHILE ip <= ep
        GOSUB GetToken
        INCR i
        IF i > UBOUND_D(tokens) THEN
            REDIM PRESERVE tokens[i+100]
        END IF
        tokens[i].mToken = tok
    WEND

    FUNCTION = i

    GetToken:
    ' RESET tok
    tok = ""
    DO
        SELECT CASE ip[0]
            CASE 34
            IF LEN(tok) = 0 THEN
                LET tok = CHR$(34)
                WHILE ip <= ep
                    INCR ip
                    LET tok = tok + CHR$(ip[0])
                    IF ip[0] = 34 THEN EXIT DO
                WEND
            END IF
            CASE 0 TO 45, 47, 127 TO 255
            IF LEN(tok) = 0 THEN
                LET tok = CHR$(ip[0])
                INCR ip
            END IF
            EXIT DO

            CASE 46, 48 TO 57
            LET tok = tok+CHR$(ip[0])

            CASE 58 TO 63
            IF LEN(tok) = 0 THEN
                LET tok = CHR$(ip[0])
                INCR ip
            END IF
            EXIT DO

            CASE 64
            LET tok = tok +"@"
            INCR ip
            WHILE ip<=ep
                SELECT CASE ip[0]
                    CASE 46, 65 TO 90, 97 TO 122
                    LET tok = tok + CHR$(ip[0])
                    INCR ip
                    REM  !  &  *  +  -  /  <  =  >  \  {
                    CASE 33, 38, 42, 43, 45, 47, 60, 61, 62, 92, 123
                    LET tok = tok + CHR$(ip[0])
                    INCR ip
                    EXIT LOOP

                    CASE ELSE
                    EXIT WHILE
                END SELECT
            WEND
            EXIT DO

                CASE 46, 65 TO 90, 97 TO 122
            IF ip+2<ep THEN
                IF (ip[0] = 68) AND (ip[1] = 79) AND (ip[2] = 123) THEN
                    LET tok = "DO{"
                    LET ip = ip + 3
                    EXIT DO
                ELSEIF (ip[0] = 73) AND (ip[1] = 70) AND (ip[2] = 123) THEN
                    LET tok = "IF{"
                    LET ip = ip + 3
                    EXIT DO
                END IF
            END IF
            LET tok = CHR$(ip[0])
            INCR ip
            WHILE ip <= ep
                SELECT CASE ip[0]
                    CASE 46, 48 TO 57, 65 TO 90, 97 TO 122
                    LET tok = tok + CHR$(ip[0])
                    INCR ip
                    CASE ELSE
                    EXIT WHILE
                END SELECT
            WEND
            EXIT DO

                CASE 91 TO 96
            IF LEN(tok) = 0 THEN
                LET tok = CHR$(ip[0])
                INCR ip
            END IF
            EXIT DO

                CASE ELSE
            IF LEN(tok) = 0 THEN
                LET tok = CHR$(ip[0])
                INCR ip
            END IF
            EXIT DO
        END SELECT

        IF ip <= ep THEN
            INCR ip
        ELSE
            EXIT DO
        END IF
    LOOP
    RETURN  ' return tok
END FUNCTION



SAMPLE RUN:


A
[
o
]
+
1
+
5
^
A
[
o
]
*
(
2
+
5
^
B
)
,
DO{
A
+
1
^
A
<
100

IF{
A
=
50

A
^
!
}
}
;

Press any key to exit




JimReeder

 :) Yes I am converting PB code:

#COMPILE EXE "..\BIN\Mint.exe"
#DIM ALL

#IF %DEF(%PB_WIN32)
  DECLARE FUNCTION zTrace LIB "zTrace32.DLL" ALIAS "zTrace" (zMessage AS STRINGZ) AS LONG
#ENDIF

$DQ = CHR$(34)

TYPE MINT_TOKEN
  mToken AS STRINGZ*256
  mTokentype AS LONG
END TYPE

ENUM TokenType
  tt_Identifier   'a variable name
  tt_Number
  tt_QuotedText
  tt_SingleQuote  ''
  tt_DoubleQuote  '""
  tt_OpenParam    '(
  tt_CloseParam   ')
  tt_OpenBracket  '[
  tt_CloseBracket ']
  tt_OpenBrace    '{
  tt_CloseBrace   '}
  tt_Equal        '=
  tt_Assignment   '^
  tt_BinaryOperator '+-*/\

END ENUM

FUNCTION PBMAIN () AS LONG
  DIM i AS LONG, r AS LONG
  DIM tokenIdx AS LONG
  DIM procText AS STRING
  DIM tokens(1) AS MINT_TOKEN
  DIM fileP AS STRING
  DIM fileN AS STRING
  DIM s AS STRINGZ *255

  procText = "A[0]+1+5^A[0]*(2+5^B),DO{A+1^A<100 IF{A=50 A^!}};"

  r = MINT_TokenizeRoutine(procText,tokens())
  FOR i=1 TO r
    #IF %DEF(%PB_WIN32)
      zTrace tokens(i).mtoken
    #ELSEIF %DEF(%PB_CC32)
      CON.PRINT tokens(i).mToken
    #ENDIF

  NEXT i
  #IF %DEF(%PB_CC32)
    CON.PRINT
    CON.PRINT "Press any key to exit"
    CON.WAITKEY$
  #ELSE
    s = INPUTBOX$("Done. Press Enter to exit")
  #ENDIF
END FUNCTION

'***********************************************************************************************
'
'***********************************************************************************************

FUNCTION MINT_TokenizeRoutine(BYVAL procText AS STRING,BYREF tokens() AS MINT_TOKEN) AS LONG

    DIM tok AS STRING
    DIM ip AS BYTE PTR
    DIM zeroip AS BYTE PTR
    DIM ep AS BYTE PTR
    DIM i AS LONG
    DIM IpStack AS ISTACKCOLLECTION
    DIM CtrlStruct AS ISTACKCOLLECTION

    FUNCTION = 0 ' assume failure

    LET IpStack = CLASS "StackCollection"
    LET CtrlStruct = CLASS "StackCollection"

    REDIM tokens(1 TO 100) AS MINT_TOKEN

    IF LEN(procText)=0 THEN procText="""MINT"""

    ip = STRPTR(procText)
    zeroip = ip
    ep = ip + LEN(procText)- 1
    i = 0
    WHILE ip<=ep
      GOSUB GetToken
      INCR i
      IF i>UBOUND(tokens) THEN REDIM PRESERVE Tokens( 1 TO i+100) AS MINT_TOKEN
      tokens(i).mtoken=tok

      #IF 0  ' to be done
      SELECT CASE AS CONST$ UCASE$(tok)
        CASE "IF{"

        CASE "DO{"

        CASE " "

        CASE ";"

        CASE "{"

        CASE "}"

        CASE ELSE

      END SELECT
      #ENDIF
    WEND
    REDIM PRESERVE Tokens(1 TO i)
    FUNCTION = i
    EXIT FUNCTION

GetToken:
      RESET tok
      DO
        SELECT CASE AS LONG @ip
          CASE 34
            IF LEN(tok)=0 THEN
               LET tok = CHR$(34)
               WHILE ip<=ep
                 INCR ip
                 LET tok = tok+CHR$(@ip)
                 IF @ip=34 THEN EXIT DO
               WEND
             END IF
          CASE 0 TO 45, 47, 127 TO 255
            IF LEN(tok) = 0 THEN
              LET tok = CHR$(@ip)
              INCR ip
            END IF
            EXIT DO

          CASE 46, 48 TO 57
            LET tok = tok+CHR$(@ip)

          CASE 58 TO 63
            IF LEN(tok) = 0 THEN
              LET tok = CHR$(@ip)
              INCR ip
            END IF
            EXIT DO

          CASE 64
            LET tok = tok +"@"
            INCR ip
            WHILE ip<=ep
              SELECT CASE AS LONG @ip
                CASE 46,65 TO 90, 97 TO 122
                  LET tok = tok + CHR$(@ip)
                  INCR ip
                REM  !  &  *  +  -  /  <  =  >  \  {
                CASE 33,38,42,43,45,47,60,61,62,92,123
                  LET tok = tok + CHR$(@ip)
                  INCR ip
                  EXIT LOOP
                CASE ELSE
                  EXIT LOOP
              END SELECT
            WEND
            EXIT DO

          CASE 46,65 TO 90, 97 TO 122
            IF ip+2<ep THEN
              IF (@ip = 68) AND (@ip[1] = 79) AND (@ip[2] = 123) THEN
                LET tok = "DO{"
                LET ip = ip + 3
                EXIT DO
              ELSEIF (@ip = 73) AND (@ip[1] = 70) AND (@ip[2] = 123) THEN
                LET tok = "IF{"
                LET ip = ip + 3
                EXIT DO
              END IF
            END IF
            LET tok = CHR$(@ip)
            INCR ip
            WHILE ip<=ep
              SELECT CASE AS LONG @ip
                CASE 46, 48 TO 57, 65 TO 90, 97 TO 122
                  LET tok = tok + CHR$(@ip)
                  INCR ip
                CASE ELSE
                  EXIT LOOP
              END SELECT
            WEND
            EXIT DO

          CASE 91 TO 96
            IF LEN(tok) = 0 THEN
              LET tok = CHR$(@ip)
              INCR ip
            END IF
            EXIT DO

          CASE ELSE
            IF LEN(tok) = 0 THEN
              LET tok = CHR$(@ip)
              INCR ip
            END IF
            EXIT DO
        END SELECT

        IF ip<=ep THEN
          INCR ip
        ELSE
          EXIT DO
        END IF
      LOOP
      RETURN  'return tok

END FUNCTION

MrBcx

Quote from: JimReeder on April 01, 2025, 04:17:52 PMI added the source file to my initial post.

Thanks ... I placed your code inside code tags.

Your code has numerous flaws that I will attempt to resolve for you.

Was this originally PowerBasic code or some other dialect of BASIC?

If so, I'd like to have the original code.


JimReeder

I added the source file to my initial post.

MrBcx

#2
Jim,

Can you share Bd_Mint_Parser.Bas?

That would make it easier to hunt for the source of the error.


JimReeder

#1
I am a new user of BCX.  Within BCX editor, when I Build my simple console application, I receive the following error:

BCX BASIC to C/C++ Translator (c) 1999-2025 by Kevin Diggins
Version 8.2.6 (03/21/2025) Compiled using LLVM-Clang (20.1.0) for 64-bit Windows
[Lines In: 201] [Lines Out: 774] [Statements: 171] [Time: 0.02 Sec's]
BCX translated [Bd_Mint_Parser.Bas] to [Bd_Mint_Parser.C] for a C Compiler
ERROR: "C:\Dev\MINTBED\Src\bd_Mint_parser".c was not found. Operation aborted.

The $FILE$.c file exists in the folder.  What am I missing in my configuration?

Some addition information is that I get the same error attempting to Build a sample Console application.

here is my source file:

$DQ = CHR$(34)

TYPE MINT_TOKEN
  mToken AS STRING
  mTokentype AS LONG
END TYPE

ENUM TokenType,_
  tt_Identifier,_  'a variable name
  tt_Number,
  tt_QuotedText,_
  tt_SingleQuote,_  ''
  tt_DoubleQuote,_  '""
  tt_OpenParam,_    '(
  tt_CloseParam,_  ')
  tt_OpenBracket,_  '[
  tt_CloseBracket,_ ']
  tt_OpenBrace,_    '{
  tt_CloseBrace,_  '}
  tt_Equal,_        '=
  tt_Assignment,_  '^
  tt_BinaryOperator '+-*/\

'END ENUM

FUNCTION MAIN () AS LONG
  DIM i AS LONG, r AS LONG
  DIM tokenIdx AS LONG
  DIM procText AS STRING
  DIM tokens[100] AS MINT_TOKEN
  DIM fileP AS STRING
  DIM fileN AS STRING
  DIM s AS STRING

  procText = "A
[o]+1+5^A
[o]*(2+5^B),DO{A+1^A<100 IF{A=50 A^!}};"

  r = MINT_TokenizeRoutine(procText,tokens())
  FOR i=1 TO r
      PRINT tokens(i).mToken
  NEXT i
  PRINT
  PRINT "Press any key to exit"
  KEYPRESS
 
END FUNCTION

'***********************************************************************************************
'
'***********************************************************************************************

FUNCTION MINT_TokenizeRoutine(BYVAL procText AS STRING,BYREF tokens AS MINT_TOKEN) AS LONG

    DIM tok AS STRING
    DIM ip AS LPSTR
    DIM zeroip AS LPSTR
    DIM ep AS LPSTR
    DIM i AS LONG
 
    FUNCTION = 0 ' assume failure
 
    REDIM tokens[100] AS MINT_TOKEN

    IF LEN(procText)=0 THEN procText="""MINT"""

    ip = STRPTR(procText)
    zeroip = ip
    ep = ip + LEN(procText)- 1
    i = 0
    WHILE ip<=ep
      GOSUB GetToken
      INCR i
      IF i>UBOUND(tokens) THEN REDIM PRESERVE tokens[i+100] AS MINT_TOKEN
      tokens(i).mtoken=tok
    WEND
    REDIM PRESERVE tokens
    FUNCTION = i
    EXIT FUNCTION

GetToken:
      'RESET tok
      tok = ""
      DO
        SELECT CASE BYTE_AT(ip
[o])
          CASE 34
            IF LEN(tok)=0 THEN
              LET tok = CHR$(34)
              WHILE ip<=ep
                INCR ip
                LET tok = tok+CHR$(BYTE_AT(ip
[o]))
                IF BYTE_AT(ip
[o])=34 THEN EXIT DO
              WEND
            END IF
          CASE 0 TO 45, 47, 127 TO 255
            IF LEN(tok) = 0 THEN
              LET tok = CHR$(BYTE_AT(ip
[o]))
              INCR ip
            END IF
            EXIT DO

          CASE 46, 48 TO 57
            LET tok = tok+CHR$(BYTE_AT(ip
[o]))

          CASE 58 TO 63
            IF LEN(tok) = 0 THEN
              LET tok = CHR$(BYTE_AT(ip
[o]))
              INCR ip
            END IF
            EXIT DO

          CASE 64
            LET tok = tok +"@"
            INCR ip
            WHILE ip<=ep
              SELECT CASE BYTE_AT(ip
[o])
                CASE 46,65 TO 90, 97 TO 122
                  LET tok = tok + CHR$(BYTE_AT(ip
[o]))
                  INCR ip
                REM  !  &  *  +  -  /  <  =  >  \  {
                CASE 33,38,42,43,45,47,60,61,62,92,123
                  LET tok = tok + CHR$(BYTE_AT(ip
[o]))
                  INCR ip
                  EXIT LOOP
                CASE ELSE
                  EXIT LOOP
              END SELECT
            WEND
            EXIT DO

          CASE 46,65 TO 90, 97 TO 122
            IF ip+2<ep THEN
              IF (BYTE_AT(ip
[o]) = 68) AND (BYTE_AT(ip[1]) = 79) AND (BYTE_AT(ip[2]) = 123) THEN
                LET tok = "DO{"
                LET ip = ip + 3
                EXIT DO
              ELSEIF (BYTE_AT(ip
[o]) = 73) AND (BYTE_AT(ip[1]) = 70) AND (BYTE_AT(ip[2]) = 123) THEN
                LET tok = "IF{"
                LET ip = ip + 3
                EXIT DO
              END IF
            END IF
            LET tok = CHR$(BYTE_AT(ip
[o]))
            INCR ip
            WHILE ip<=ep
              SELECT CASE BYTE_AT(ip
[o])
                CASE 46, 48 TO 57, 65 TO 90, 97 TO 122
                  LET tok = tok + CHR$(BYTE_AT(ip
[o]))
                  INCR ip
                CASE ELSE
                  EXIT LOOP
              END SELECT
            WEND
            EXIT DO

          CASE 91 TO 96
            IF LEN(tok) = 0 THEN
              LET tok = CHR$(BYTE_AT(ip
[o]))
              INCR ip
            END IF
            EXIT DO

          CASE ELSE
            IF LEN(tok) = 0 THEN
              LET tok = CHR$(BYTE_AT(ip
[o]))
              INCR ip
            END IF
            EXIT DO
        END SELECT

        IF ip<=ep THEN
          INCR ip
        ELSE
          EXIT DO
        END IF
      LOOP
      RETURN  'return tok

END FUNCTION