' Finite State Machine — SELECT CASE based parsing
#COMPILE EXE
#DIM ALL

CONST STATE_IDLE = 0
CONST STATE_READING = 1
CONST STATE_COMMENT = 2
CONST STATE_STRING = 3
CONST STATE_NUMBER = 4

SUB SimpleTokenizer(text AS STRING)
    LOCAL i AS LONG
    LOCAL ch AS STRING
    LOCAL state AS LONG
    LOCAL token AS STRING
    LOCAL q AS STRING
    q = CHR$(34)
    state = STATE_IDLE
    token = ""
    PRINT "=== TOKENIZER STATE MACHINE ==="
    PRINT "Input: " + text
    PRINT "Tokens:"
    FOR i = 1 TO LEN(text)
        ch = MID$(text, i, 1)
        SELECT CASE state
            CASE STATE_IDLE
                IF (ch >= "A" AND ch <= "Z") OR (ch >= "a" AND ch <= "z") THEN
                    state = STATE_READING
                    token = ch
                ELSEIF ch >= "0" AND ch <= "9" THEN
                    state = STATE_NUMBER
                    token = ch
                ELSEIF ch = "'" THEN
                    state = STATE_COMMENT
                ELSEIF ch = q THEN
                    state = STATE_STRING
                    token = ""
                END IF
            CASE STATE_READING
                IF (ch >= "A" AND ch <= "Z") OR (ch >= "a" AND ch <= "z") OR (ch >= "0" AND ch <= "9") THEN
                    token = token + ch
                ELSE
                    PRINT "  [IDENT] " + token
                    state = STATE_IDLE
                END IF
            CASE STATE_NUMBER
                IF (ch >= "0" AND ch <= "9") OR ch = "." THEN
                    token = token + ch
                ELSE
                    PRINT "  [NUMBER] " + token
                    state = STATE_IDLE
                END IF
            CASE STATE_COMMENT
                PRINT "  [COMMENT] " + MID$(text, i)
                EXIT FOR
            CASE STATE_STRING
                IF ch <> q THEN
                    token = token + ch
                ELSE
                    PRINT "  [STRING] " + token
                    state = STATE_IDLE
                END IF
        END SELECT
    NEXT i
    IF state = STATE_READING THEN PRINT "  [IDENT] " + token
    IF state = STATE_NUMBER THEN PRINT "  [NUMBER] " + token
    PRINT
END SUB

SUB CSVParser()
    LOCAL outLine AS STRING
    LOCAL i AS LONG
    LOCAL ch AS STRING
    LOCAL f AS STRING
    LOCAL fc AS LONG
    LOCAL inQ AS LONG
    LOCAL q AS STRING
    q = CHR$(34)
    outLine = "John,Doe,42,Engineer"
    inQ = 0
    f = ""
    fc = 0
    PRINT "=== CSV PARSER ==="
    PRINT "Input: " + outLine
    PRINT "Fields:"
    FOR i = 1 TO LEN(outLine)
        ch = MID$(outLine, i, 1)
        IF ch = "," AND inQ = 0 THEN
            fc = fc + 1
            PRINT "  Field " + STR$(fc) + ": " + f
            f = ""
        ELSEIF ch = q THEN
            IF inQ THEN inQ = 0 ELSE inQ = 1
        ELSE
            f = f + ch
        END IF
    NEXT i
    IF LEN(f) > 0 THEN
        fc = fc + 1
        PRINT "  Field " + STR$(fc) + ": " + f
    END IF
    PRINT
END SUB

SUB BinaryCounter()
    LOCAL i AS LONG
    LOCAL bit AS LONG
    LOCAL state AS LONG
    LOCAL outLine AS STRING
    LOCAL b2(0 TO 7) AS LONG
    b2(0) = 1
    b2(1) = 2
    b2(2) = 4
    b2(3) = 8
    b2(4) = 16
    b2(5) = 32
    b2(6) = 64
    b2(7) = 128
    PRINT "=== BINARY COUNTER (3-bit) ==="
    state = 0
    FOR i = 0 TO 7
        outLine = "State " + STR$(state) + " (binary: "
        FOR bit = 2 TO 0 STEP -1
            IF state AND b2(bit) THEN
                outLine = outLine + "1"
            ELSE
                outLine = outLine + "0"
            END IF
        NEXT bit
        outLine = outLine + ")"
        PRINT outLine
        state = state + 1
    NEXT i
    PRINT
END SUB

SUB TrafficLight()
    LOCAL i AS LONG
    LOCAL state AS LONG
    PRINT "=== TRAFFIC LIGHT FSM ==="
    state = 0
    FOR i = 1 TO 10
        SELECT CASE state
            CASE 0
                PRINT "Cycle " + STR$(i) + ": GREEN"
                state = 1
            CASE 1
                PRINT "Cycle " + STR$(i) + ": YELLOW"
                state = 2
            CASE 2
                PRINT "Cycle " + STR$(i) + ": RED"
                state = 0
        END SELECT
    NEXT i
    PRINT
END SUB

SUB ParseExpression(expr AS STRING)
    LOCAL i AS LONG
    LOCAL ch AS STRING
    LOCAL state AS LONG
    LOCAL result AS LONG
    LOCAL op AS LONG
    LOCAL val AS LONG
    state = 0
    op = 0
    result = 0
    val = 0
    PRINT "=== EXPRESSION PARSER ==="
    PRINT "Input: " + expr
    FOR i = 1 TO LEN(expr)
        ch = MID$(expr, i, 1)
        SELECT CASE state
            CASE 0
                IF ch >= "0" AND ch <= "9" THEN
                    val = VAL(ch)
                    state = 1
                END IF
            CASE 1
                IF ch = "+" THEN
                    IF op = 0 THEN result = val
                    IF op = 1 THEN result = result + val
                    IF op = 2 THEN result = result - val
                    op = 1
                    val = 0
                    state = 0
                ELSEIF ch = "-" THEN
                    IF op = 0 THEN result = val
                    IF op = 1 THEN result = result + val
                    IF op = 2 THEN result = result - val
                    op = 2
                    val = 0
                    state = 0
                ELSEIF ch >= "0" AND ch <= "9" THEN
                    val = val * 10 + VAL(ch)
                END IF
        END SELECT
    NEXT i
    IF op = 0 THEN result = val
    IF op = 1 THEN result = result + val
    IF op = 2 THEN result = result - val
    PRINT "Result = " + STR$(result)
    PRINT
END SUB

FUNCTION PBMAIN() AS LONG
    PRINT "Finite State Machine Demos"
    PRINT ""
    CALL SimpleTokenizer("count = 42 ' this is a comment")
    CALL CSVParser()
    CALL BinaryCounter()
    CALL TrafficLight()
    CALL ParseExpression("10+25-7")
    PRINT "Done."
    FUNCTION = 0
END FUNCTION
