    '****************************************
    ' EXPRESSION EVALUATOR - PC Magazine 1993
    '****************************************
     
    '#lookahead
     
    $FILENAME "ExprEval.exe"
    'uses rtl32
    'uses rtl64
    uses Console
      
    INDEXBASE 0

    #lookahead     

    DIM AS LONG   idx      = 0
    DIM AS LONG   contin   = TRUE
    DIM AS BYTE   NextChar
    DIM AS STRING Expr // ML: may come from memory, not only from console
     
    Main
     
    '***********************************************************
    '  GetNextChar - Reads chars until a non-space char is found
    '***********************************************************
    SUB GetNextChar()
            DIM AS BYTE b AT STRPTR Expr
     
            DO 
                    NextChar = b[idx]
                    idx++
            LOOP WHILE NextChar AND (NextChar = 32 /*Asc("0")*/) // ML: memory overrun check added
    END SUB
     
    '**************************************************************
    ' Expression - A recursive routine that evaluates an expression
    ' EXPRESSION = <EXPRESSION> + TERM | <EXPRESSION> - <TERM>
    '**************************************************************
    FUNCTION Expression() AS SINGLE
            DIM AS SINGLE value = Term()
     
            DO
                    SELECT NextChar
                            CASE 32 // Asc(" ")
                                    GetNextChar
                            CASE 43 // Asc("+")
                                    GetNextChar
                                    value += Term()
                            CASE 45 // Asc("-")
                                    GetNextChar
                                    value -= Term()
                            CASE ELSE
                                    RETURN value
                    END SELECT
            LOOP
    END FUNCTION
     
    '************************************************************
    ' Term - Handles multiplication and division
    ' <TERM> = <TERM> * <FACTOR> | <TERM> div <FACTOR> | <FACTOR>
    '************************************************************
    FUNCTION Term() AS SINGLE
            DIM AS SINGLE divisor, value = Factor()
     
            DO
                    SELECT NextChar
                            CASE 32 // Asc(" ")
                                    GetNextChar
                            CASE 42 // Asc("*")
                                    GetNextChar
                                    value *= Factor()
                            CASE 94 // Asc("^")
                                    GetNextChar
                                    value = value ^ Factor() // ML: ^= isn't supported in O2
                            CASE 47 // Asc("/")
                                    GetNextChar
                                    divisor = Factor()
                                    IF divisor <> 0 THEN // ML: avoid O2-specific INFinities
                                            value /= divisor
                                    ELSE
                                            PRINT "DIVISION BY ZERO" CR CR "Press any key to exit ..."
                                            WAITKEY
                                            TERMINATE 
                                    END IF
                            CASE ELSE
                                    RETURN value
                    END SELECT
            LOOP
    END FUNCTION
     
    '**************************************************
    ' Factor - Handles numbers, minus signs and parens
    ' <FACTOR> = <EXPRESSION> | <VARIABLE> | <CONSTANT>
    '**************************************************
    FUNCTION Factor() AS SINGLE
            DIM AS SINGLE value = 0
            DIM AS LONG i, count = 0, d_point = FALSE
            DIM AS BYTE b AT STRPTR Expr
     
            IF (NextChar <= 57 /*Asc("9")*/) AND (NextChar >= 48 /*Asc("0")*/) THEN
                    WHILE (NextChar <= 57) AND (NextChar >= 48)
                            value *= 10 + NextChar - 48 // Asc("0")
                            NextChar = b[idx]
                            idx++
                            IF d_point THEN count++
                            IF NextChar = 46 /*Asc(".")*/ THEN
                                    NextChar = b[idx]
                                    idx++
                                    d_point = TRUE
                            END IF
                    WEND
                    FOR i = 0 TO i < count
                            value /= 10
                    NEXT
                    RETURN value
            ELSE
                    SELECT NextChar
                            CASE 45 // Asc("-")
                                    GetNextChar
                                    RETURN -1 * Factor()
                            CASE 40 // Asc("(")
                                    GetNextChar
                                    value = Expression()
                                    IF NextChar <> 41 /*Asc(")")*/ THEN
                                            PRINT "MISMATCHED PARENTHESES" CR CR "Press any key to exit ..."
                                            WAITKEY
                                            TERMINATE
                                    ELSE
                                            NextChar = b[idx]
                                            idx++
                                    END IF
                                    RETURN value
                            CASE 46 // Asc(".")
                                    d_point = TRUE
                            CASE ELSE
                                    contin = FALSE
                    END SELECT
            END IF
            RETURN 0
    END FUNCTION
     
    '***************************
    ' Main - Program entry point
    '***************************
    SUB MAIN()
            DIM AS SINGLE result
     
            SetConsoleTitle "Aurel's Expression Evaluator"
     
            PRINT "Expression must not contain any other symbol but:" CR
            PRINT "'+'      addition" CR "'-'       subtraction" CR
            PRINT "'*'      multiplication" CR "'/' division" CR
            PRINT "'('      left parenthesis" CR "')'       right parenthesis" CR
            PRINT "'.'      decimal point (must be preceded by digit)" CR
            PRINT "'^'      x^y means x to the power of y" CR CR
            PRINT "ENTER EXPRESSION:        "
     
            Expr = INPUT // ML: try e.g. "(1+2)*(6-3)" instead of INPUT
            GetNextChar
            result = Expression()
     
            IF ((NextChar = 13 /*console*/) OR (NextChar = 0 /*memory*/)) AND contin THEN
                    PRINT "RESULT IS:               " STR(result, 3)
            ELSE
                    PRINT "SYNTAX ERROR"
            END IF
            PRINT CR CR "Press any key to exit ..."
            WAITKEY
    END SUB