Qbasicnews.com

Full Version: Expression evaluator
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2 3 4 5 6
Well, I fixed things here and there and added support for parentheses. It wasn't that hard. I had problems with the part I had already coded 'cause it read the expressions from left to right... (silly me: recursion works upside down when it is NOT FINAL!!). I've written my own INSTR string which searches from END to BEGINNING.

Parentheses processing takes 22 lines Sad

Code:
DECLARE FUNCTION instrRev% (st1$, st2$)
DECLARE FUNCTION eval% (cmd$)
CLS
PRINT eval%("3+(-3*4+(3-4*(4+3)))")
PRINT
PRINT 3 + (-3 * 4 + (3 - 4 * (4 + 3)))

FUNCTION eval% (cmd$)
   ' Preprocess parentheses **********************************************
   Init% = 1
   DO
      a% = INSTR(Init%, cmd$, "(")
      IF a% <> 0 THEN
         Init% = a% + 1: np% = 1: Ps% = Init%: Res$ = ""
         DO
            IF Ps% > LEN(cmd$) THEN ' Unbalanced Parentheses!
               Res$ = "0": Ps% = Init% + 1
               EXIT DO
            END IF
            m$ = MID$(cmd$, Ps%, 1)
            IF m$ = ")" AND np% = 1 THEN EXIT DO
            Res$ = Res$ + m$
            Ps% = Ps% + 1
            IF m$ = "(" THEN np% = np% + 1
            IF m$ = ")" THEN np% = np% - 1
         LOOP
         r% = eval%(Res$)
         cmd$ = LEFT$(cmd$, Init% - 2) + STR$(r%) + RIGHT$(cmd$, LEN(cmd$) - Ps%)
      END IF
   LOOP WHILE a% <> 0
   ' *********************************************************************
  
   cmd$ = LTRIM$(RTRIM$(cmd$))

   a% = instrRev%(cmd$, "+")
   b% = instrRev%(cmd$, "-")

   IF a% = 0 AND b% = 0 THEN
      a% = instrRev%(cmd$, "*")
      b% = instrRev%(cmd$, "/")
      IF a% = 0 AND b% = 0 THEN
         Res% = VAL(cmd$)
      ELSE
         IF a% > b% THEN
            Res% = eval%(LEFT$(cmd$, a% - 1)) * eval%(RIGHT$(cmd$, LEN(cmd$) - a%))
         ELSE
            Res% = eval%(LEFT$(cmd$, b% - 1)) / eval%(RIGHT$(cmd$, LEN(cmd$) - b%))
         END IF
      END IF
   ELSE
      ' Detect Unary "-" and remove:
      IF b% > 1 THEN
         lp$ = RTRIM$(LEFT$(cmd$, b% - 1))
         IF RIGHT$(lp$, 1) <= "0" OR RIGHT$(lp$, 1) >= "9" THEN b% = 0
      END IF
      IF a% > b% THEN
         Res% = eval%(LEFT$(cmd$, a% - 1)) + eval%(RIGHT$(cmd$, LEN(cmd$) - a%))
      ELSE
         Res% = eval%(LEFT$(cmd$, b% - 1)) - eval%(RIGHT$(cmd$, LEN(cmd$) - b%))
      END IF
   END IF
   eval% = Res%
END FUNCTION

FUNCTION instrRev% (st1$, st2$)
   Res% = 0
   FOR i% = LEN(st1$) TO 1 STEP -1
      IF MID$(st1$, i%, 1) = st2$ THEN Res% = i%: EXIT FOR
   NEXT i%
   instrRev% = Res%
END FUNCTION
in qb code, this is what one gets:

Code:
DECLARE FUNCTION reduce.string$ (string1$)
DEFINT A-Z
CLS
PRINT reduce.string$("5 + 5 * 13")

FUNCTION reduce.string$ (string1$)

string1$ = "(" + string1$ + ")"
DO
read.loc = 1
start.p = 0
op$ = ""
string2$ = ""
string3$ = ""
op.exists = 0
num1$ = ""
num2$ = ""
num3$ = ""
st$ = ""
i = 0
j = 0
string1a$ = ""
string1b$ = ""

'get the location of the innermost parentheses

DO
start.p = INSTR(read.loc, string1$, "(")
IF start.p = 0 THEN EXIT DO
read.loc = start.p + 1
LOOP

'find the end of the parentheses-enclosed statement.
end.loc = INSTR(read.loc, string1$, ")")

'removing the innermost ( ), save everything before as string2, everything after as string3, and extract the parentheses-enclosed statement as string1.

string2$ = MID$(string1$, 1, read.loc - 2)
IF LEN(string1$) - end.loc > 0 THEN string3$ = MID$(string1$, 1 + end.loc, LEN(string1$) - end.loc) ELSE string3$ = ""
string1$ = MID$(string1$, read.loc, end.loc - read.loc)

'find an operand, starting from the left and going in the order: /, *, -, +
DO
op.exists = INSTR(string1$, "/ "): IF op.exists THEN op$ = "/": GOTO ex1
op.exists = INSTR(string1$, "* "): IF op.exists THEN op$ = "*": GOTO ex1
op.exists = INSTR(string1$, "- "): IF op.exists THEN op$ = "-": GOTO ex1
op.exists = INSTR(string1$, "+ "): IF op.exists THEN op$ = "+" ELSE EXIT DO
ex1:
'operate on the two numbers left and right of the operand.
'PRINT string2$ + "(" + string1$ + ")" + string3$
num1$ = "": num2$ = ""
i = op.exists - 2
DO
st$ = MID$(string1$, i, 1)
IF INSTR("-0123456789/", st$) <> 0 THEN
num2$ = st$ + num2$
ELSE
EXIT DO
END IF
i = i - 1
IF i = 0 THEN EXIT DO
LOOP

j = i: i = op.exists + 2
DO
st$ = MID$(string1$, i, 1)
IF INSTR("-0123456789/", st$) <> 0 THEN
num1$ = num1$ + st$
ELSE
i = i - 1
EXIT DO
END IF
IF i = LEN(string1$) THEN EXIT DO
i = i + 1
LOOP

SELECT CASE op$
CASE "+": num3$ = LTRIM$(STR$(VAL(num1$) + VAL(num2$)))
CASE "-": num3$ = LTRIM$(STR$(VAL(num1$) - VAL(num2$)))
CASE "*": num3$ = LTRIM$(STR$(VAL(num1$) * VAL(num2$)))
CASE "*": num3$ = LTRIM$(STR$(VAL(num2$) / VAL(num1$)))
END SELECT

string1a$ = MID$(string1$, 1, j)
string1b$ = MID$(string1$, i + 1, LEN(string1$) - i)
string1$ = string1a$ + num3$ + string1b$

LOOP

'now set the value of the function
string1$ = string2$ + string1$ + string3$
IF INSTR(string1$, " ") = 0 THEN EXIT DO
LOOP
reduce.string$ = string1$
END FUNCTION
Ok guys, this is a working version of Agamemnus' original idea. You complie this program once. It generates a one line program called eee.bas which it compiles and runs. I have a batch file called COMPILE which it invokes to compile the eee.bas program. You can make it a bit more fancy, but you can't get any simpler.
Code:
rem EXPRESSION EVALUATOR --- LET BASIC DO THE WORK.
INPUT "Enter expression to evaluate ";e$
open "eee.bas" for output as #1
open "eee.exe" for output as #2  Â´create so can kill.
print #1,"print "+e$
print #2,"xxx"
close
kill "eee.exe"           'In case of compile error.
shell "COMPILE eee"
cls
run "eee"
Q.E.D.
*****
A little bit slow, isn't it? Big Grin
Very funny, Nathan.
*****
Cool na_th_an, but it doesnt work with: 2 * -3

And aga, yours works with 2 * -3, but doesnt work with 2+(3), it says the answer is (2 + 3), but if you put that back into the function it simplifies it again, so repedatively your one pretty much works perfectly as far as i can see Smile
Nexinarius, that's because I erroneously added an EXIT DO right before the last LOOP. It shouldn't be there.
Quote:Cool na_th_an, but it doesnt work with: 2 * -3

And aga, yours works with 2 * -3, but doesnt work with 2+(3), it says the answer is (2 + 3), but if you put that back into the function it simplifies it again, so repedatively your one pretty much works perfectly as far as i can see Smile

You're right. I forgot a case.
I can fix that, but I'll do it tomorrow Smile
@aga: o ok.

edit: i removed it, and it didnt seem to fix it.
Yes it did.

The function only works with spaces. 5+5 won't work right. (notice qb works with spaces too, BUT it also reformats 5+5 into 5 + 5)

However, my program doesn't reformat. That should be the job of the input statement. Smile
Pages: 1 2 3 4 5 6