'****************************************
' EXPRESSION EVALUATOR - PC Magazine 1993
'****************************************
#AUTODIM OFF
#LOOKAHEAD
$FILENAME "ExprEval.exe"
'INCLUDE "rtl32.inc"
'INCLUDE "rtl64.inc"
INCLUDE "Console.inc"
INDEXBASE 0
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