5. Multiple operators

Of course we want to be able to have multiple operators which the parser can handle: -, +, /, * and ^ for example. Therefore we will expand the function Eval such that it handles these different operators in the right mathematical order. First we will search for minus (-), then for addition (+), then division (/), multiplication (*) and at last power (^). In this way we keep up the right mathematical precedence (parsing rule 2).

One way is just to copy the content of Eval five times and adjust the code for each different operator. But because these five routines are almost equal, it's handier to write it in a loop. To do this, we use the following FOR-NEXT loop:

FOR n=1 TO 5
    operator = MID$("-+/*^", n, 1)
    
    '... code here ...
    
NEXT n

By introducing the operators minus (-) and division (/) we must be aware to follow the third parsing rule: find the last occurance of the operator. Else things will mess up with expressions like "10-3-4". To do this, in the following example is a function InstrRev() written. This function works in the same way as Instr() exept that it finds the last occurance of the seached text.

SUB InstrREV(expr:STRING, search:STRING, posmax:INT), INT
    'returns the position of the last string search in the string expr,
    ' before position posmax
    INT n, p
    p=0	:n=0
    DO
        p = INSTR(expr, search, p+1)
        p = p*(p<=posmax)
        IF p>0 THEN n=p
    UNTIL p=0
    
    RETURN n
ENDSUB

Example 2
The complete code for the new expression parser is now as presented below (Example 2).

Example 2
/*
Recursive expression parser, Example 2.
Written with IBasic Professional
By Jos de Jong, may 2006

Supports expressions with operators + - * / ^
*/
AUTODEFINE "Off"
DEF inputexpr:STRING

OPENCONSOLE

'print some examples of expressions with their answers
PRINT "Expression Calculator"
PRINT "You can use + - * / ^"
PRINT "Enter an expression and press Enter to calculate it."
PRINT "Enter an empty expression to quit"
PRINT ""
PRINT "Examples:"
PRINT "2 + 3 * 4 = ", Eval("2 + 3 * 4")
PRINT "2 + 3 / 4 - 5 = ", Eval("2 + 3 / 4 - 5")
PRINT "2.5 ^ 3.25 = ", Eval("2.5 ^ 3.25")
PRINT ""
DO
    'ask the user to enter an expression. After this the expression
    'will be evaluated and the answer will be printed
    INPUT ">>", inputexpr
    IF RTRIM$(inputexpr)<>""
        PRINT "    Ans = ", Eval(inputexpr)
    ENDIF
UNTIL RTRIM$(inputexpr)=""

'end the program
CLOSECONSOLE
END

'_____________________________________________________________________
SUB Eval(Expression:STRING), DOUBLE
    DEF pos, n:INT
    DEF expr:STRING
    DEF part1, part2:STRING
    DEF operator:STRING

    'remove spaces at start and end of the expression
    expr = LTRIM$(RTRIM$(Expression))

    FOR n=1 TO 5
        'choose an operator
        '(for each loop choose the following of the five operators)
        operator = MID$("-+/*^", n, 1)

        'search for the last occurance of this operator
        pos = InstrREV(expr, operator, 255)
        IF pos
            'there is an operator found at position pos. Split up the
            'expression in two parts and calculate the result of that
            'two parts. Then calculate the result for the complete
            'expression.
            part1 = LEFT$(expr, pos-1)
            part2 = RIGHT$(expr, LEN(expr)-pos)

            'now execute the calculation between left and right part,
            'and return the answer
            SELECT operator
                CASE "-"
                    RETURN Eval(part1) - Eval(part2)
                CASE "+"
                    RETURN Eval(part1) + Eval(part2)
                CASE "/"
                    RETURN Eval(part1) / Eval(part2)
                CASE "*"
                    RETURN Eval(part1) * Eval(part2)
                CASE "^"
                    RETURN Eval(part1) ^ Eval(part2)
            ENDSELECT
        ENDIF
    NEXT n

    'there are no more operators left in the expression, and the
    'expression is not solved yet so the expression must be a value
    'return the value
    RETURN VAL(expr)
ENDSUB

'_____________________________________________________________________
SUB InstrREV(expr:STRING, search:STRING, posmax:INT), INT
    'returns the position of the last string search in the string expr,
    ' before position posmax
    INT n, p
    p=0	:n=0
    DO
        p = INSTR(expr, search, p+1)
        p = p*(p<=posmax)
        IF p>0 THEN n=p
    UNTIL p=0

    RETURN n
ENDSUB



Copyright 2006 SpeQ Mathematics