5. Multiple operatorsOf 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
The complete code for the new expression parser is now as presented below (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